How to create an RXjs RetryWhen with delay and limit on tries
You need to apply the limit to the retry signal, for instance if you only wanted 10 retries:
loadSomething(): Observable<SomeInterface> {
return this.http.get(this.someEndpoint, commonHttpHeaders())
.retryWhen(errors =>
// Time shift the retry
errors.delay(500)
// Only take 10 items
.take(10)
// Throw an exception to signal that the error needs to be propagated
.concat(Rx.Observable.throw(new Error('Retry limit exceeded!'))
);
EDIT
Some of the commenters asked how to make sure that the last error is the one that gets thrown. The answer is a bit less clean but no less powerful, just use one of the flattening map operators (concatMap, mergeMap, switchMap) to check which index you are at.
Note: Using the new RxJS 6 pipe
syntax for future proofing (this is also available in later versions of RxJS 5).
loadSomething(): Observable<SomeInterface> {
const retryPipeline =
// Still using retryWhen to handle errors
retryWhen(errors => errors.pipe(
// Use concat map to keep the errors in order and make sure they
// aren't executed in parallel
concatMap((e, i) =>
// Executes a conditional Observable depending on the result
// of the first argument
iif(
() => i > 10,
// If the condition is true we throw the error (the last error)
throwError(e),
// Otherwise we pipe this back into our stream and delay the retry
of(e).pipe(delay(500))
)
)
));
return this.http.get(this.someEndpoint, commonHttpHeaders())
// With the new syntax you can now share this pipeline between uses
.pipe(retryPipeline)
}