How to use retryWhen only 3 times then give up
How to use retryWhen only 3 times then give up
I want to filter when specific exception occurs during execution of some of the upper chain function and try to retry the whole process only 3 times then if it still failes then give up. I came to something like this:
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!")
})
How to do it properly?
2 Answers
2
You may use zipWith with a range to achieve this.
zipWith
range
.retryWhen { errors -> errors.zipWith(Observable.range(1, 3), { _, i -> i }) }
The retryWhen operator gives you the stream of all the errors from your source publisher. Here you zip these with numbers 1, 2, 3. Therefore the resulting stream will emit 3 next followed by the complete. Contrary to what you may think this resubscribes only twice, as the complete emitted immediately after the third next causes the whole stream to complete.
retryWhen
next
complete
complete
next
You may extend this further, by retrying only for some errors, while immediately failing for others. For example, if you want to retry only for IOException, you may extend the above solution to:
IOException
.retryWhen { errors -> errors
.zipWith(Observable.range(1, 3), { error, _ -> error })
.map { error -> when (error) {
is IOException -> error
else -> throw error
}}
}
Since map cannot throw a checked exception in Java, Java users may use flatMap for the same purpose.
map
flatMap
I think what you're trying to do can be achieved with retry exclusively:
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) })
Output:
someMethod called
someMethod2 called
Attempt# 1
someMethod called
someMethod2 called
Attempt# 2
someMethod called
someMethod2 called
Attempt# 3
Exception someMethod2
As someMethod2 always throws an Exception, after 3 attempts Exception someMethod2 is printed in onError of the observer.
someMethod2
Exception
Exception someMethod2
onError
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.