Reputation: 1533
I'm implementing an observable which retries on error after a delay of 5s. I'm using retrofit for networking. The problem i'm facing is that there are a lot of retries when the API returns an error. I want to retry only after 5s but the retry happens at an insane rate(almost three times in a second). Any idea why?
userAPI.getUsers()
.filter { it.users.isNotEmpty() }
.subscribeOn(Schedulers.io())
.retryWhen { errors -> errors.flatMap { errors.delay(5, TimeUnit.SECONDS) } }
.observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {})
where userAPI.getUsers()
returns an observable.
Insane number of API requests:
08-13 12:31:31.308 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:31.825 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:32.370 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:32.897 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:33.436 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:33.952 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:34.477 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:35.020 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:35.609 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
08-13 12:31:36.205 26277-26453/com.app.user.dummy D/OkHttp: --> GET https://userapi.com/foo
P.S: i've already gone through the blog post by Dan lew on retryWhen and repeatWhen.
Upvotes: 1
Views: 1067
Reputation: 106
Please look into Dan Lew's blog post again where he actually describes a solution for your use case under Uses title.
source.retryWhen(errors -> errors.flatMap(error -> Observable.timer(5, TimeUnit.SECONDS)))
Explanation:
Notice the difference between Observable.delay
and Observable.timer
as Observable.delay
's documentation states that
Error notifications from the source Observable are not delayed.
In retryWhen your errors
Observable is subscribed to immediately (as Observable.delay
only delays onNext) and then the source errors out again and immediately emits the error, that triggers retryWhen and you enter a recursive loop.
Upvotes: 5
Reputation: 3083
The problem seems to be in your flatmap function lambda i.e.
.retryWhen({ errors -> errors.flatMap { errors.delay(5, TimeUnit.SECONDS) } })
(I'm assuming the lack of brackets is a typo). The result is that the Observable that gets passed to retryWhen immediately terminates resulting in the "insane" retry rate when you get an error.
Try
userAPI.getUsers()
.filter { it.users.isNotEmpty() }
.subscribeOn(Schedulers.io())
.retryWhen({ errors -> errors.flatMap { error -> Observable.just(1).delay(5, TimeUnit.SECONDS) } })
.observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {})
Upvotes: -1