进行观察,直到事件N到达订阅者,然后发出事件N + 1

时间:2018-08-02 20:28:36

标签: java rx-java reactive-programming rx-java2 vert.x

我在vertx中继承了一个可观察的链,其中:

  • 定期发射
  • 查询一些状态
  • 查找第二组状态
  • 回写第一状态的不同版本

它看起来像这样:

Scheduler defaultScheduler = RxHelper.scheduler(vertx);
Scheduler blockingScheduler = RxHelper.blockingScheduler(vertx)
Observable.interval(/* some time */)
          .observeOn(blockingScheduler)
          .flatMapIterable(t -> getRecords())
          .observeOn(defaultScheduler)
          .flatMap(record -> Observable.just(record)
                                       .flatMap(getRecordDetails(record))
                                       .observeOn(blockingScheduler)
                                       .doOnNext(sendRecordDetails(detail))
                                       .observeOn(defaultScheduler)
                                       .doOnNext(markDetailAsSeenInLocalCache(detail))
                                       .onErrorReturn(e -> false)
                                       .all(success -> success)))
          .doOnNext(persistLocalCacheToJsonFileOnDisk())
          .subscribe( m -> {/* nothing */}, e -> {/* handle fatal error */});

我的问题是,如果在getRecords()的最后一次调用N之前调用sendRecordDetails()进行迭代N + 1,那么我们就有竞争条件。

我对Rx / vertx中的调度没有专业的了解,但是我认为,如果这些全部放在defaultScheduler上,那么可能可以。但是,当我们想进行异步阻塞IO时想知道阻塞调度程序时,这放弃了defaultScheduler使用的主事件循环,这意味着它将消失并开始为第一个interval中的下一个事件提供服务可观察的。

在最坏的情况下,如果迭代N sendRecordDetails()长时间挂起,则可能导致迭代N + 1在迭代N之前完成。

我必须承认我的第一个直觉是“也许我们不应该为此使用Rx”。但是我已经继承了这段代码,因此我至少需要尝试看看是否有一种获得保证的惯用方法,然后才能断言这是一个丢失的原因,需要重写为其他样式。

我想到的最接近的想法是将订阅写入并发队列,并用zipWith(interval(/* some time */, observableWhichEmitsItemsFromConcurrentQueue)代替初始间隔。这似乎有点像我在强迫框架执行不应执行的操作。另外,看起来我必须自己实现可观察到的并发队列。

所以我的问题是:强迫一个可观察的对象在事件N通知用户之前不发出事件N + 1的最合理方法是,还是强迫框架做一些本不该做的事情干嘛?

编辑:

这是一个迫使事件在发出下一个事件之前到达订阅者的示例。没有主题的序列是A,A1,A,A1,B,C,B,C,有主题的序列是A,A1,B,C,A,A1,B,C。我可以正确使用Subject(包括序列化)吗?

@Test
public void baz() throws InterruptedException {
    BlockingDeque<Object> blockingDequed = new LinkedBlockingDeque<>();
    Vertx vertx = Vertx.vertx();
    Scheduler d = RxHelper.scheduler(vertx);
    Scheduler b = RxHelper.blockingScheduler(vertx);

    X x = new X();

    Subject<Object> publishSubject = PublishSubject.create();

    int blockTime = 1;
    Observable.zip(publishSubject.serialize(), Observable.range(1,2), (i, j) -> j)
            .observeOn(d)
            .doOnNext(i -> logWithName(i, "A"))
            .doOnNext(i -> block(blockTime)) //blocks for blockTime seconds
            .doOnNext(i -> logWithName(i, "A1"))
            .concatMap( j -> Observable.just(j).observeOn(d)
                    .doOnNext(i -> block(blockTime))
                    .doOnNext(i -> logWithName(i, "B"))
            )
            .observeOn(d)
            .doOnNext(i -> logWithName(i, "C"))
            .doOnNext(i -> publishSubject.onNext(new Object()))
            .doOnComplete(() -> blockingDequed.add(new Object()))
            .subscribe();
    publishSubject.onNext(new Object());

    blockingDequed.poll(1, TimeUnit.DAYS);
}

0 个答案:

没有答案