Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Throw error after the retry fails with Angular http.get

I'm trying to implement Angular5 http.get with retry. I wrote

http.get<any>('/api/study').retryWhen(
    (errors: Observable<any>):Observable<any> => {
        return errors.flatMap((error: any) => {
            if (error.status  == 500) {
                return Observable.of(error.status).delay(1000);
            }
            return Observable.throw(error);
        }).take(5);
    });

This will keep retrying up to 5 times if it gets error 500. However, if it gets 5 failures in a row, then it returns success (with null data). I don't want that. Instead I want it to throw the last error.

I tried to put .concat(Observable.throw({})) after the take(), and that works, but it does not give me any information, such as the status code of the most recent error.

How can I get the most recent error after the last retry fails?

like image 900
John Henckel Avatar asked Mar 21 '26 13:03

John Henckel


2 Answers

You don't need to use take(5) to count the failed attempts and count it yourself using a local variable.

For example you could do this:

http.get<any>('/api/study').retryWhen((errors: Observable<any>) => {
    let errors = 0;

    return errors.flatMap((error: any) => {
        if (errors++ < 5 && error.status  == 500) {
            return Observable.of(error.status).delay(1000);
        }
        return Observable.throw(error);
    });
});
like image 147
martin Avatar answered Mar 24 '26 02:03

martin


.retryWhen can only complete or error - in both cases, further retries are aborted. See docs.

So when you add .take(5) you are basically telling it to retry 5 times and then complete, at which point it can ONLY complete (and therefore cannot ALSO return an error - it is either one or the other, not both).

So using .take() will not solve your issue.

Unfortunately this means you have to keep track of the retry count yourself WITHIN the retryWhen - so for 5 counts you just let it return the error (which will trigger the retry), and finally on count 6 you manually throw an error. You can then catch that final error in a catch block.

Something like this (code not tested but shows the idea):

http.get<any>('/api/study').retryWhen(err => {
    console.log('retrying');
    let retries = 0;
    return err
      .delay(1000)
      .map(error => {
        if (retries++ === 6) {
          console.log('retry number ', retries);
          throw error; <- THIS WILL CAUSE retryWhen to complete
        }
        return error; 
      });
  })
  .catch(err => {
    console.log('caught');
    return Observable.of(err);
  })
  .subscribe(data => {
    console.log('subscriber');
    console.log(data);
  });

As a side note, adding .concat(Observable.throw({})) doesn't solve your problem, because when that fires, your 5 retries are done and hence the retryWhen has completed (ie. returned complete, so no error). This is why the concat cannot throw the last error, because it never received it.

like image 36
rmcsharry Avatar answered Mar 24 '26 01:03

rmcsharry



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!