我在整个Reactor文档中一直在阅读,但我无法找到以下问题的正确模式。 我有一个应该异步做某事的方法。我以Flux的形式返回结果响应,消费者可以订阅它。
该方法有以下定义:
Flux<ResultMessage> sendRequest(RequestMessage message);
返回的通量是一个热通量,结果可以在任何给定的时间异步进入。
潜在消费者可以通过以下方式使用它:
sendRequest(message).subscribe(response->doSomethinWithResponse(response);
实现可以是这样的:
Flux<ResultMessage> sendRequest(RequestMessage message) {
Flux<ResultMessage> result = incomingMessageStream
.filter( resultMessage -> Objects.equals( resultMessage.getId(), message.getId() ) )
.take( 2 );
// The message sending is done here...
return result;
}
incomingMessageStream
是通过此频道的所有邮件的Flux
。
这个实现的问题是消费者在结果消息到来之后被订阅,并且它可能会遗漏其中一些消息。
所以,我正在寻找的解决方案将允许消费者不依赖订阅时间。潜在消费者可能根本不需要订阅结果Flux
。我正在寻找一般解决方案,但如果不可能,您可以假设结果消息的数量不大于2.
答案 0 :(得分:0)
一段时间后,我创建了一个似乎有效的解决方案:
Flux<ResultMessage> sendRequest(RequestMessage message) {
final int maxResponsesCount = 2;
final Duration responseTimeout = Duration.ofSeconds( 10 );
final Duration subscriptionTimeout = Duration.ofSeconds( 5 );
// (1)
ConnectableFlux<ResultMessage> result = incomingMessageStream
.ofType( ResultMessage.class )
.filter( resultMessage ->Objects.equals(resultMessage.getId(), message.getId() ) )
.take( maxResponsesCount )
.timeout( responseTimeout )
.replay( maxResponsesCount );
Disposable connectionDisposable = result.connect();
// (2)
AtomicReference<Subscription> subscriptionForCancelSubscription = new AtomicReference<>();
Mono.delay( subscriptionTimeout )
.doOnSubscribe( subscriptionForCancelSubscription::set )
.subscribe( x -> connectionDisposable.dispose() );
// The message sending is done here...
// (3)
return result
.doOnSubscribe(s ->subscriptionForCancelSubscription.get().cancel())
.doFinally( signalType -> connectionDisposable.dispose() );
}
我使用ConnectableFlux立即连接到流,没有订阅,设置为使用reply()方法存储所有消息,因此稍后的任何订阅者都不会错过响应消息(1)。
可以执行的路径很少:
调用方法并订阅流量
2.1。没有回复消息
.timeout( responseTimeout )
)。之后.doFinally(..)
清理资源(1)(3)。2.2。已返回一些响应消息
2.3。已返回所有响应消息
doFinally()
)执行.take( maxResponsesCount )
(1)(3)我还没有对此进行一些严肃的测试,如果出现问题,我会在这个答案中添加更正。