我想过滤某些上链函数在执行过程中何时发生特定异常,并尝试仅重试整个过程3次,如果仍然失败,则放弃。我来到了这样的地方:
val disposable = someFunction(someParameter, delay, subject)
.flatMapCompletable { (parameter1, parameter2) ->
anotherFunction(parameter1, parameter2, subject)
}
.retryWhen { throwable ->
throwable.filter {
it.cause?.cause is ExampleException1
|| it.cause?.cause is ExampleException2
|| it.cause is ExampleException3
}
}
.andThen(someStuff())
.subscribe({
Timber.d("Finished!")
}, {
Timber.d("Failed!")
})
如何正确执行?
答案 0 :(得分:3)
您可以将zipWith
与range
配合使用。
.retryWhen { errors -> errors.zipWith(Observable.range(1, 3), { _, i -> i }) }
retryWhen
运算符为您提供了来自源发布者的所有错误流。在这里用数字1、2、3压缩它们。因此,结果流将发出3 next
,后跟complete
。与您可能会认为它只重新订阅两次相反,因为在第三个complete
之后立即发出的next
导致整个流完成。
您可以通过仅重试某些错误而又立即使其他错误失败来进一步扩展此范围。例如,如果您只想重试IOException
,则可以将上述解决方案扩展到:
.retryWhen { errors -> errors
.zipWith(Observable.range(1, 3), { error, _ -> error })
.map { error -> when (error) {
is IOException -> error
else -> throw error
}}
}
由于map
在Java中无法引发检查异常,因此Java用户可以出于相同目的使用flatMap
。
答案 1 :(得分:1)
我认为您可以尝试完全通过retry
来实现:
val observable = Observable.defer {
System.out.println("someMethod called")
val result1 = 2 // some value from someMethod()
Observable.just(result1)
}
observable.flatMap { result ->
// another method is called here but let's omit it for the sake of simplicity and throw some exception
System.out.println("someMethod2 called")
throw IllegalArgumentException("Exception someMethod2")
Observable.just("Something that won't be executed anyways")
}.retry { times, throwable ->
System.out.println("Attempt# " + times)
// if this condition is true then the retry will occur
times < 3 && throwable is IllegalArgumentException
}.subscribe(
{ result -> System.out.println(result) },
{ throwable -> System.out.println(throwable.localizedMessage) })
输出:
someMethod称为
someMethod2称为
尝试#1
someMethod称为
someMethod2称为
尝试#2
someMethod称为
someMethod2称为
尝试#3
Exception someMethod2
由于someMethod2
总是抛出Exception
,因此在观察者的Exception someMethod2
中打印了3次onError
。
答案 2 :(得分:0)
具有指数延迟的代码:
YourSingle()
.retryWhen { errors: Flowable<Throwable> ->
errors.zipWith(
Flowable.range(1, retryLimit + 1),
BiFunction<Throwable, Int, Int> { error: Throwable, retryCount: Int ->
if (error is RightTypeOfException && retryCount < retryLimit) {
retryCount
} else {
throw error
}
}
).flatMap { retryCount ->
//exponential 1, 2, 4
val delay = 2.toDouble().pow(retryCount.toDouble()).toLong() / 2
Flowable.timer(delay, TimeUnit.SECONDS)
}
}