I am trying to make an API call (using angular4), which retries when it fails, using retryWhen. I want it to delay for 500 ms and retry again. This can be achieved with this code:
loadSomething(): Observable<SomeInterface> { return this.http.get(this.someEndpoint, commonHttpHeaders()) .retryWhen(errors => errors.delay(500)); }
But this will keep trying forever. How do I limit it to, let's say 10 times?
Thank you!
RxJS retry() operator is an error-handling operator that returns an observable that mirrors the source observable except for an error.
take returns an Observable that emits only the first count values emitted by the source Observable. If the source emits fewer than count values then all of its values are emitted. After that, it completes, regardless if the source completes.
ReTry & ReTryWhen Operators help us to retry a failed observable in Angular. These operators are useful in Error handling. They both resubscribe to the source observable when they receive onError() notification.
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) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With