目前我正在使用Observable.retry(n)以便在出错时重试。请看一下这段代码:
@Test
public void testObservableRetry() {
Observable
.<String>defer(() -> Observable
.just(Notification.createOnNext("valid value"), Notification.createOnError(new Error("Test")))
.dematerialize())
.doOnNext(v -> System.out.println("onNext: " + v))
.doOnError(e -> System.out.println("onError: " + e.getMessage()))
.doOnSubscribe(d -> System.out.println("onSubscribe"))
.doOnDispose(() -> System.out.println("onDispose"))
.retry(2)
.take(2) // .take(4) will fail the test
.blockingLast();
}
上述代码能够在出错后恢复,但重试次数受限于总错误数而非连续错误。
E.g。如果您将.take(2)
替换为.take(4)
- 测试将失败,因为总错误数将超过4,尽管每次错误后它都会恢复并且能够获得下一个值:
---(v1)----(error)---(v2)----(error)----(v3)-----(error)---(v4)-
我想在恢复成功后找到一种重置计数器的方法。用例例如是网络连接 - 我想在每次断开连接时给出相同数量的尝试,但是在每次成功连接之后我想重置计数器以便允许无限流量,除非每次它能够恢复在不断尝试的次数内。
修改
在此上下文中成功恢复意味着在重试后收到至少1个项目。所以我想只限制连续错误的数量,而不是总错误。
答案 0 :(得分:2)
这只是一点点修改@ akarnokd的解决方案(只是移除nonEmpty
标志)。 @akarnokd - 免费编辑您的解决方案,我将删除此解决方案。
static <T> ObservableTransformer<T, T> retryEmpty(int count) {
return o -> {
AtomicInteger remaining = new AtomicInteger(count);
return o.doOnNext(v -> remaining.lazySet(count))
.retryWhen(err -> err.flatMap(e ->
(remaining.decrementAndGet() == 0)
? Observable.<T>error(e)
: Observable.just(1)));
};
}
答案 1 :(得分:1)
您需要retryWhen
并在流程之前与其进行通信:
@Test
public void emptyError() {
AtomicInteger c = new AtomicInteger();
Observable.fromCallable(() -> { throw new Exception("" + c.incrementAndGet()); })
.compose(retryEmpty(2))
.test()
.assertFailureAndMessage(Exception.class, "2");
}
@Test
public void nonEmptyError() {
Observable.just(1).concatWith(Observable.error(new Exception()))
.compose(retryEmpty(2))
.take(4)
.test()
.assertResult(1, 1, 1, 1);
}
static <T> ObservableTransformer<T, T> retryEmpty(int count) {
return o ->
Observable.defer(() -> {
AtomicInteger remaining = new AtomicInteger(count);
AtomicBoolean nonEmpty = new AtomicBoolean();
return o.doOnNext(v -> nonEmpty.lazySet(true))
.retryWhen(err ->
err.flatMap(e -> {
if (nonEmpty.get()) {
nonEmpty.lazySet(false);
remaining.lazySet(count);
} else
if (remaining.decrementAndGet() == 0) {
return Observable.error(e);
}
return Observable.just(1);
})
);
});
}