RxJava 2.0 - 处理publish()中未捕获的子类错误的资源.refCount()

时间:2017-02-06 23:35:56

标签: java exception-handling rx-java rx-java2

我对RxJava很陌生,并且 - 正如其他许多人一样 - 我正在努力解决异常处理问题。我在网上阅读了不少帖子(例如此处的讨论how to handle exceptions thrown by observer's onNext)和认为我已经了解了概念的基本概念。

在上述讨论中,其中一张海报说,当订阅者抛出异常时,RxJava会执行以下操作:

  

实施通用处理以记录失败并停止向其发送事件   (任何类型的)并清理由于该订户而携带的任何资源   任何剩余的订阅。

这或多或少都是我看到的,我唯一遇到的问题是"清理任何资源"位。为清楚起见,我们假设以下示例:

我想创建一个Observable,它在每个收到的消息上监听异步事件源(例如JMS队列)和onNext()。所以在(伪)代码中我会做类似的事情:

Observable<String> observable = Observable.create( s -> {
  createConnectionToBroker();
  getConsumer().setMessageListener(message -> s.onNext(transform(message)));
  s.setDisposable(new Disposable() {
    public void dispose() {
      tearDownBrokerConnection();
    }
  });
});

由于我想为许多订阅者/观察者重用消息监听器,我不直接订阅创建的Observable,而是使用publish()。refCount()团队。类似的东西:

Observable<String> observableToSubscribeTo = observable.publish().refCount();

Disposable d1 = observableToSubscribeTo.subscribe(s -> ...);
Disposable d2 = observableToSubscribeTo.subscribe(s -> ...);

这一切都按预期工作。代码仅在第一个订阅建立时连接到JMS,并且当最后一个观察者为dispose()时,与代理的连接将关闭。

然而,当订阅者在onNext()时抛出异常时,事情似乎变得混乱。正如预期的那样,投掷的观察者已经被激活,每当发布新事件时,它都不会再被通知。我的问题似乎是当所有剩余订户都为dispose() d时,不再通知维护与消息代理的连接的Observable。它看起来好像抛出异常的订阅者处于某种僵尸状态。它在事件分发时会被忽略,但它会以某种方式阻止根Observable在最后一个订阅者dispose() d时收到通知。

我理解RxJava希望观察者确保不会抛出,而是正确处理最终异常。不幸的是,在我想提供一个向调用者返回一个Observable的库的情况下,我无法控制我的订阅者。这意味着,我永远无法保护我的图书馆免受愚蠢的观察者的侵害。

所以,我问自己:我在这里错过了什么吗?当用户抛出时,真的没有机会正确清理吗?这是一个错误还是只是我不理解图书馆?

任何见解都非常感谢!

1 个答案:

答案 0 :(得分:1)

如果你能展示一些能够证明问题(不需要JMS)的单元测试,那就太棒了。

此外,RxJava 2中的onNext永远不会抛出;如果它确实是一个未定义的行为。如果您不信任您的消费者,您可以使用safeSubscribe而不是普通subscribe的终端可观察变换器,以增强对下游行为不端的保护:

.compose(o -> v -> o.safeSubscribe(v))

.compose(new ObservableTransformer<T>() {
    @Override public Observable<T> apply(final Observable<T> source) {
        return new Observable<T>() {
            @Override public void subscribeActual(Observer<? super T> observer) {
                 source.safeSubscribe(observer);
            }
        };
    }
})