如何不依赖Reactor的订阅时间

时间:2018-04-12 16:35:13

标签: java reactive-programming project-reactor

我在整个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.

1 个答案:

答案 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)。

可以执行的路径很少:

  1. 调用方法并且没有对通量执行订阅
    • 解决方案 - 如果没有订阅,有一个计时器可在5秒后删除连接的磁通资源。 (2)
  2. 调用方法并订阅流量

    2.1。没有回复消息

    • 解决方案 - 设置获取响应的超时(.timeout( responseTimeout ))。之后.doFinally(..)清理资源(1)(3)。

    2.2。已返回一些响应消息

    • 解决方案 - 与2.1相同。

    2.3。已返回所有响应消息

    • 解决方案 - 由于达到的最大元素数量(doFinally())执行.take( maxResponsesCount )(1)(3)
  3. 我还没有对此进行一些严肃的测试,如果出现问题,我会在这个答案中添加更正。