当前位置: 首页 > 知识库问答 >
问题:

如何处理RxJava中observer的onNext引发的异常?

葛宪
2023-03-14

考虑以下示例

Observable.range(1, 10).subscribe(i -> {
    System.out.println(i);

    if (i == 5) {
        throw new RuntimeException("oops!");
    }
}, Throwable::printStackTrace);

这将输出从1到5的数字,然后打印异常。

我想要实现的是使观察器保持订阅状态,并在抛出异常后继续运行,即打印从1到10的所有数字。

我尝试过使用retry()和其他各种错误处理操作符,但正如文档中所述,它们的目的是处理可观察对象本身发出的错误。

最直接的解决方案是将onNext的整个主体包装成一个try-catch块,但对我来说这听起来不是一个好的解决方案。在类似的Rx中。NET问题,提出的解决方案是制作一个扩展方法,该方法将通过创建一个可观察的代理来进行包装。我试图重新制作它:

Observable<Integer> origin = Observable.range(1, 10);
Observable<Integer> proxy = Observable.create((Observable.OnSubscribe<Integer>) s ->
        origin.subscribe(i -> {try { s.onNext(i); } catch (Exception ignored) {}}, s::onError, s::onCompleted));

proxy.subscribe(i -> {
    System.out.println(i);

    if (i == 5) {
        throw new RuntimeException("oops!");
    }
}, Throwable::printStackTrace);

这不会改变任何事情,因为RxJava本身将订阅者包装成一个安全订阅者。使用unsafeSubscribe来绕过它似乎也不是一个好的解决方案。

我能做些什么来解决这个问题?

共有1个答案

笪成周
2023-03-14

这是学习Rx时出现的常见问题。

您建议将异常处理逻辑放在订阅服务器中,而不是创建一个通用的可观察包装器。

记住,Rx是关于将事件推送到订阅者。

从可观察的接口中,很明显,除了处理事件花费了多长时间,或者任何抛出的异常中包含的信息之外,可观察的用户实际上无法了解它的订阅者。

一个通用的包装器来处理订阅者异常并继续向订阅者发送事件是个坏主意。

为什么?那么,可观察者应该只知道订阅者现在处于未知的故障状态。在这种情况下继续发送事件是不明智的,例如,订阅者可能处于这样一种情况,即从现在开始的每个事件都会抛出一个异常,并需要一段时间才能完成。

一旦订阅者抛出异常,对于可观察到的情况,只有两个可行的操作过程:

  • 重新引发异常
  • 实现通用处理,以记录故障并停止向其发送事件(任何类型),清理由于该订阅者而产生的任何资源,并继续进行任何剩余订阅

具体处理订阅者异常将是一个糟糕的设计选择;这将在订阅者和可观察者之间产生不适当的行为耦合。因此,如果你想对不好的订阅者保持弹性,上述两种选择实际上是可观察对象自身责任的合理限制。

如果您希望您的订阅者具有弹性并继续使用,那么您绝对应该将其包装在异常处理逻辑中,该逻辑旨在处理您知道如何从中恢复的特定异常(也许还可以处理瞬态异常、日志记录、重试逻辑、断路等)。

只有订阅者本身才有上下文来理解它是否适合在出现故障时接收进一步的事件。

如果您的情况需要开发可重用的错误处理逻辑,请将自己放在包装观察者的事件处理程序而不是可观察事件处理程序的心态中,并且注意不要在出现故障时盲目地传输事件。放开它!虽然不是关于Rx的,但这是一部有趣的软件工程经典,在最后一点上有很多话要说。如果你还没有读过,我强烈建议你。

 类似资料:
  • 问题内容: 考虑以下示例: 这将输出从1到5的数字,然后打印异常。 我要实现的是使观察者保持订阅状态,并在引发异常后继续运行,即打印从1到10的所有数字。 我曾尝试使用和其他各种错误处理运算符,但是,正如文档中所述,它们的目的是处理可观察对象自身发出的错误。 最直接的解决方案是将整个过程包装到try- catch块中,但这对我来说似乎不是一个好的解决方案。在类似的Rx.NET问题中,提出的解决方案

  • 我正在处理一个Spring启动应用程序。我尝试处理异常。但我想我这样做的方式有问题,因为它总是抛出内部服务器错误500。 我尝试设置自定义异常类,并且还使用带有@响应状态的响应状态代码。但是不管异常是什么,它只会抛出内部服务器错误。我使用的是intellij,我在异常中给出的消息打印在那里,但响应正文empty.This我想一定是因为它抛出了内部服务器错误。 控制器类 intellij 中的终端打

  • 我正试图自己解决参数问题。 我可以很容易地从NativeWebRequest获取输入参数,并将它们分派到相应的自定义@Param注释参数中。 问题是我还想在这方面做一些语法检查/验证。但如果我在“resolveArgument”中抛出异常,则会向用户显示完整的堆栈跟踪。这将是过度和不安全的。我只想向用户返回一条JSON格式的消息,以显示哪个输入参数语法有错误。

  • 我目前正试图把精力放在RxJava上,但我在以优雅的方式处理服务调用异常方面遇到了一点麻烦。 基本上,我有一个(改型)服务,它返回一个。的定义如下: 现在,我想要的是将该泛型响应映射到data JsonElement字段中包含的(我假设您不关心对象的外观,所以我不会用它污染文章)。下面的代码对于success案例非常有效,但是我找不到一个很好的方法来处理我的API异常: 有没有更好的办法做到这一点

  • 问题内容: 我有一个生成器和一个使用它的函数: 如果生成器引发异常,我想在使用者函数中处理该异常,然后继续使用迭代器,直到耗尽为止。请注意,我不想在生成器中有任何异常处理代码。 我想到了类似的东西: 但这对我来说看起来很尴尬。 问题答案: 这也是我不确定是否正确/优雅处理的事情。 我要做的是从生成器中获取一个,然后将其提升到其他位置。喜欢: 这样,我仍然继承了Exception而没有引发它,这将导

  • 那么,是否有一些Spring机制,我可以在其中注册一个捕获视图错误的异常处理程序?