我正在学习Reactor,我想知道如何实现某种行为。 让我们说我有一串传入的消息。 每条消息都与某个实体相关联,并包含一些数据。
interface Message {
String getEntityId();
Data getData();
}
可以并行处理与不同实体相关的消息。
但是,必须一次处理一个与任何单个实体有关的消息,即实体"abc"
的消息2的处理在实体"abc"
的消息1的处理完成之前不能开始。
在处理消息时,应该缓冲该节点的进一步消息。
其他实体的消息可以不受阻碍地进行。
人们可以将其视为每个实体运行代码的线程如下:
public void run() {
for (;;) {
// Blocks until there's a message available
Message msg = messageQueue.nextMessageFor(this.entityId);
// Blocks until processing is finished
processMessage(msg);
}
}
如何在没有阻止的情况下使用React实现这一目标? 总消息速率可能很高,但每个实体的消息速率将非常低。 实体集可能非常大,并且不一定事先知道。
我想它可能看起来像这样,但我不知道。
{
incomingMessages()
.groupBy(Message::getEntityId)
.flatMap(entityStream -> entityStream
/* ... */
.map(msg -> /* process the message */)))
/* ... */
}
public static Stream<Message> incomingMessages() { /* ... */ }
答案 0 :(得分:2)
答案 1 :(得分:0)
我们在项目中遇到了同样的问题。具有相同ID的实体必须顺序处理,但是具有不同ID的实体可以并行处理。
解决方案非常简单。代替使用flatMap我们开始使用concatMap。来自concatMap的文档:
* Transform the elements emitted by this {@link Flux} asynchronously into Publishers,
* then flatten these inner publishers into a single {@link Flux}, sequentially and
* preserving order using concatenation.
代码示例:
public void receive(Flux<Data> data) {
data
.groupBy(Data::getPointID)
.flatMap(service::process)
.onErrorContinue(Logging::logError)
.subscribe();
}
处理方法:
Flux<SomeEntity> process(Flux<Data> dataFlux) {
return dataFlux
.doOnNext(Logging::logReceived)
.concatMap(this::proceedDefinitionsSearch)
.doOnNext(Logging::logDefSearch)
.flatMap(this::processData)
.doOnNext(Logging::logDataProcessed)
.concatMap(repository::save)
.doOnNext(Logging::logSavedEntity);
}