Project Reactor(或RxJava2)执行器序列调用

时间:2018-11-28 12:45:52

标签: java functional-programming rx-java2 project-reactor

我有以下任务,我想使用Project Reactor(或RxJava)解决它

有事件的来源。每个事件都由serviceId和一些有效负载组成。收到事件后,我们需要对带有有效负载的指定serviceId执行操作。但是我们应该确保对同一serviceId的两个请求之间的时间间隔必须大于或等于一秒。但是对差异服务的请求可以并行执行。

我们还应该注意,服务数量是动态的。

它看起来像下图

enter image description here

目前,我有以下代码:

Flux.create((sink-> eventProvider.listen(new EventListner(){
                public void event(req) {
                    sink.next(req);
                }
            })))
        /* need some logic here */
        .flatMap(req -> requestExecutor.execute(req))
        .doOnNext(res -> responseProcessor.process(res))
        .subscribe();

您有什么想法吗?

2 个答案:

答案 0 :(得分:0)

如果事件标识了它们发起调用的服务,则可以使用groupBy()运算符按服务分隔流。要在每个服务请求之后引入延迟,请使用flatMap()和参数将使用情况单线程化。

在RxJava中:

observable
  .groupBy(event -> getServiceId( event )) // 1
  .flatMap(serviceObservable -> // 2
       serviceObservable // 3
         .flatMap( ev -> service(serviceObservable.getKey(), ev), 1) // 4
                           .delay(1, TimeUnit.SECONDS)) // 5
  .subscribe();
  1. 通过事件将使用的服务对事件进行分组。稍后,该ID将作为密钥服务器。遇到新的服务ID时,它将发出新的项目。
  2. serviceObservableGroupByObservable,将在下面进行处理。
  3. 此可观察到的每个发射都是一个事件,应该将其提供给单个服务。
  4. serviceObservable.getKey()返回要使用的服务的ID。我发明了一种方法service(),该方法通过服务的ID将事件发送到服务。另外,参数1告诉flatMap()对操作进行单线程处理,因此一次只能发生一个服务请求。
  5. delay()(或您想要的任何操作员)将等待一秒钟,然后再释放操作。

(免责声明:此代码未经测试,但在过去的项目中我进行了类似的调度,因此基本思想是合理的。)

答案 1 :(得分:0)

Flux.groupBy()在这种情况下会为您提供帮助。 操作员使用映射器功能创建键,并根据键将发射的元素分组在一起。您可以将serviceId作为密钥。

Flux.create((sink-> eventProvider.listen(new EventListner(){
            public void event(req) {
                sink.next(req);
            }
        })))
    .groupBy(req -> req.getServiceId()) //group req by serviceId
    .flatMap(reqGroup-> reqGroup..delayElements(Duration.ofSeconds(1)) //add minimum delay to the group
    .flatMap(req -> requestExecutor.execute(req))
    .doOnNext(res -> responseProcessor.process(res))
    .subscribe();

您还可以根据serviceId添加不同的延迟。请以下面的代码段为例进行检查-偶数整数将延迟2秒秒,奇数延迟1秒。

    Flux.range(1, 20)
    .groupBy(integer -> integer % 2)
    .flatMap(integerGroupedFlux -> {
      Flux<Integer> integerFlux;
      if (integerGroupedFlux.key() == 0) { //even integers
        integerFlux = integerGroupedFlux.delayElements(Duration.ofSeconds(2));
      } else {
        integerFlux = integerGroupedFlux.delayElements(Duration.ofSeconds(1));
      }
      return integerFlux;
    })
    .subscribe(System.out::println);