簡體   English   中英

如何處理RxJava中觀察者的onNext引發的異常?

[英]How to handle exceptions thrown by observer's onNext in RxJava?

請考慮以下示例:

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

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

這將輸出1到5之間的數字,然后打印異常。

我想要實現的是讓觀察者保持訂閱並在拋出異常后繼續運行,即打印從1到10的所有數字。

我已經嘗試過使用retry()其他各種錯誤處理操作符 ,但是,如文檔中所述,它們的目的是處理observable本身發出的錯誤。

最直接的解決方案就是將整個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本身將訂閱者包裝到SafeSubscriber 使用unsafeSubscribe來解決它似乎也不是一個好的解決方案。

我該怎么做才能解決這個問題?

這是學習Rx時出現的常見問題。

TL; DR

您將異常處理邏輯放在訂閱者中的建議優於創建通用可觀察包裝器。

說明

請記住,Rx是關於將事件推送給訂閱者。

從可觀察的界面可以清楚地看出,除了處理事件所花費的時間或任何拋出異常中包含的信息之外,沒有任何觀察者可以知道它的訂閱者。

處理訂戶異常並繼續向該訂戶發送事件的通用包裝器是一個壞主意。

為什么? 那么observable應該只知道訂戶現在處於未知的故障狀態。 在這種情況下繼續發送事件是不明智的 - 例如,訂閱者處於這樣一種情況:從這一點開始的每個事件都將拋出異常並花費一些時間來完成它。

一旦訂閱者拋出異常,對於observable只有兩個可行的操作過程:

  • 重新拋出異常
  • 實施通用處理以記錄故障並停止向其發送事件(任何類型)並清理由於該訂戶而導致的任何資源並繼續進行任何剩余訂閱。

對訂戶異常的具體處理將是一個糟糕的設計選擇; 它會在訂閱者和可觀察者之間產生不適當的行為耦合。 因此,如果您想要對不良訂閱者具有彈性,那么上述兩種選擇實際上是可觀察者本身的合理責任限制。

如果您希望您的訂戶具有彈性並繼續運行,那么您應該將其包裝在異常處理邏輯中,該邏輯旨在處理您知道如何從中恢復的特定異常 (並且可能處理瞬態異常,記錄,重試邏輯,斷路等) )。

只有訂戶本身才具有上下文,以了解在面對失敗時是否適合接收更多事件。

如果您的情況需要開發可重復使用的錯誤處理邏輯,請將自己置於包裝觀察者事件處理程序而不是可觀察事件的思維模式中 - 並且注意不要盲目地在失敗時繼續傳輸事件。 發布吧! 雖然沒有關於Rx的文章,但是有趣的軟件工程經典在這最后一點上有很多話要說。 如果你還沒看過,我強烈建議。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM