Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an RXjs RetryWhen with delay and limit on tries

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!

like image 775
Tomer Almog Avatar asked Jul 04 '17 17:07

Tomer Almog


People also ask

What is retry in RxJS?

RxJS retry() operator is an error-handling operator that returns an observable that mirrors the source observable except for an error.

What is Take operator in RxJS?

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.

What is retry in angular?

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.


1 Answers

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) } 
like image 175
paulpdaniels Avatar answered Sep 20 '22 12:09

paulpdaniels