我试图用rx-java构建一个健壮的处理管道,但我遇到了一个问题。
以下是一个例子:
public static void main(String[] args) {
AtomicInteger div = new AtomicInteger(-1);
Observable.just(1, 1, 1).map(item -> 1 / div.getAndIncrement())
.retry().subscribe(item -> System.out.println(item));
}
这种情况下的输出是4项,因为非流可观察性被重放,但这不相关,所以为了简单起见,请忽略它。我添加了评论,显示了达到结果的计算和重新订阅的重点:
-1 // 1 / -1
// 1/0 (error) - resubscribes to observable
1 // 1 / 1
0 // 1 / 2
0 // 1 / 3
这是因为retry
运算符(作为所有重试运算符)在传递错误通知后导致重新订阅。
我的预期输出是:
-1 // 1 / -1
// 1/0 (error) - resubscribe but resume erroneous item (1)
1 // 1 / 1
0 // 1 / 0
当传递错误通知时,重新订阅过程应该在流中包含错误的项目(在同一项目上重试) - 因为错误是外部的并且没有嵌入到已处理的项目中(因此重新处理会使义)。
这是一些外部错误(如数据库连接)的情况,我喜欢未处理的项目会有一些延迟重新处理。我知道使用标准的重试操作符可以重新订阅,但是所有这些操作都会放弃错误的项目。
我还考虑过将我的所有处理包装在try-catch中,我怀疑错误是可能的,但是我的处理代码中添加了样板代码,我不想这样做。
所以我的问题是:是否有标准的方法可以在失败的项目上重试?
我已经考虑过做(未经测试)的事情:
someSubject.flatMap(
item-> Observable.just(item)
.doOnError(err -> someSubject.onNext(item))).onErrorX...
并压制错误......
但这似乎不自然,在我的使用案例中也很昂贵(为每个项目创建一个observable)。
是否有操作符或操作符组合可能导致重试将错误的项目传回到observable的开头而没有" break"或将物品包装在不同的可观察物中?
这也是我过去使用async-retry时的重试方式。
答案 0 :(得分:7)
这通常不适用于RxJava。如果元素的处理失败,则没有从该位置恢复的内置方式。您可以做的最好的事情是尝试捕获有问题的函数回调并手动重试。第二个最好的事情是使用flatMap
,其中可能有问题的计算是可以单独重试的内部Observable
:
source.flatMap(v ->
Observable.just(v).map(v -> v / counter.getAndIncrement()).retry()
)