I'm trying to use retryWhen
in HTTP calls.
It works perfectly when try to use like this:
return this.http.get(`${environment.apiUrl}/track/${this.user.instance._id}/${this.currentPlayer.playlist.id}/next?s=${this.playerCounter}`, options)
.timeout(500, new TimeoutError(`Timeout trying to get next track. [instanceId=${this.user.instance._id}]`))
.retryWhen(attempts => {
return Observable.range(1, 3).zip(attempts, i => i).flatMap(i => 3 === i ? Observable.throw(attempts) : Observable.timer(i * 1000));
})
It makes a maximum of 3 tries if get a Timeout error.
But, always have a buuut, I want to make this more abstract to use on various use cases and for this, I have to check the type of the error.
Only TechnicalErros will be retried.
So I tried this without success.
.retryWhen(attempts => {
return attempts.flatMap(error => {
if(error instanceof TechnicalError) {
return Observable.range(1, 3).zip(attempts, i => i).flatMap(i => 3 === i ? Observable.throw(attempts) : Observable.timer(i * 1000));
} else {
Observable.throw(error);
}
});
})
It stops at first try and does not execute the Observable.timer()
, neither the Observable.throw()
.
I have almost sure that the problem is about the first flatMap
, I already tried to use mergeMap
, without success.
Thanks in advance!
I came across same issue and found a way to use range operator to generate the retries count instead of the counter variable, here is the code:
The idea is to place the range operator where it will be initialized only once (the retryWhen callback) this way the zip operator will combine any error with a new range number and pass this to the map operator to do the error check logic
In RxJS 5
flatMap()
is just alias tomergeMap()
:).The problem is in the way you use the callback for
retryWhen()
operator. It's called just once and then every time an error signal arrives it's pushed to the Observable returned from this callback.In your second example you're returning Observable from
attempts.flatMap
and then subscribing to it again that callback with.zip(attempts, i => i)
. But thiszip
operator is never called because it's called after the value has been already consumed byattempts.flatMap
. Also this is why theObservable.range(1, 3)
starts always from the beginning.I know this looks confusing. Just be aware thet:
retryWhen()
is called just once.attempts.flatMap()
is called every time an error arrives.So you just need to restructure your code, for example like the following:
This prints to console:
See live demo: https://jsbin.com/hobeda/3/edit?js,console