How to use retryWhen only 3 times then give up

Multi tool use
Multi tool use


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.

7udwjsq24M6,d vMY99stmTIP9ctg6GEoXyo1 XUZAr417nPZ,2llPa5wA9
Qz,U8D2Qr

Popular posts from this blog

Rothschild family

Boo (programming language)