我有以下任务,我想使用Project Reactor(或RxJava)解决它
有事件的来源。每个事件都由serviceId和一些有效负载组成。收到事件后,我们需要对带有有效负载的指定serviceId执行操作。但是我们应该确保对同一serviceId的两个请求之间的时间间隔必须大于或等于一秒。但是对差异服务的请求可以并行执行。
我们还应该注意,服务数量是动态的。
它看起来像下图
目前,我有以下代码:
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();
您有什么想法吗?
答案 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();
serviceObservable
是GroupByObservable
,将在下面进行处理。serviceObservable.getKey()
返回要使用的服务的ID。我发明了一种方法service()
,该方法通过服务的ID将事件发送到服务。另外,参数1
告诉flatMap()
对操作进行单线程处理,因此一次只能发生一个服务请求。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);