Home > Net >  RxJs retryWhen throwing exception before all retry attempt
RxJs retryWhen throwing exception before all retry attempt

Time:08-22

I'm trying to implement an api call that will be

  1. retried few times if there is any errors
  2. after a specific time delay
  3. with some other condition check like - if returned success response json has any field null, I'll retry the api call

I tried to implement what is mentioned here - Rxjs Retry with Delay function

Following is my code segment

Api call

    delay = 5000;
    retryCount = 5;
    return this.httpClient.post(http://localhost:8080/info,JSON.stringify(data))
    .pipe(
      retryWhen(errors => 
          errors.pipe(
            delay(this.delay), 
            take(this.retryCount),
            tap(val => {
              console.log('Retrying.');
            }),
            concatMap(() => Observable.throw(new Error('Retry limit exceeded!')))
          )
        )
    );

Processing the response

this.searchService.searchInfo(param1, param2).subscribe(data => { this.handleSuccessResponse(data) }, (error) => {
        if (error) {
          // Handle specific error here
          handleErrorResponse(error);
        }
});


handleSuccessResponse(data){
  // handle success response here
}

handleErrorResponse(error){
  // Handle generic error here
}

The issue I am getting, before retrying for 5 times as I mentioned in the code, the exception in the concatMap is getting throwed. What I am missing here?

I'm using RxJS 6.4 with Angular12

CodePudding user response:

I went through the learnRxjs docs and got this generic method, which seems to satisfy your requirement!

import { Observable } from 'rxjs/Observable';
import { _throw } from 'rxjs/observable/throw';
import { timer } from 'rxjs/observable/timer';
import { mergeMap, finalize } from 'rxjs/operators';

export const genericRetryStrategy =
  ({
    maxRetryAttempts = 3,
    scalingDuration = 1000,
    excludedStatusCodes = [],
  }: {
    maxRetryAttempts?: number;
    scalingDuration?: number;
    excludedStatusCodes?: number[];
  } = {}) =>
  (attempts: Observable<any>) => {
    return attempts.pipe(
      mergeMap((error, i) => {
        const retryAttempt = i   1;
        // if maximum number of retries have been met
        // or response is a status code we don't wish to retry, throw error
        if (
          retryAttempt > maxRetryAttempts ||
          excludedStatusCodes.find((e) => e === error.status)
        ) {
          return _throw('Retry limit exceeded!');
        }
        console.log(
          `Attempt ${retryAttempt}: retrying in ${
            retryAttempt * scalingDuration
          }ms`
        );
        // retry after 1s, 2s, etc...
        return timer(retryAttempt * scalingDuration);
      }),
      finalize(() => console.log('We are done!'))
    );
  };

forked stackblitz

CodePudding user response:

case 1

  • res === null always repeat (delay 500ms)
  • Just retry API Error 5 times (delay 500ms)
api$.pipe(
    repeat({ delay: 500 }),
    skipWhile((res) => res === null),
    take(1),
    retry({ count: 5, delay: 500 })
).subscribe(observer);

Repeat HTTP call until the desired value is returned with RxJs

case 2

  • res === null API Error = 5 times (delay 500ms)
api$.pipe(
    skipWhile((res) => res === null),
    throwIfEmpty(),
    retry({ count: 5, delay: 500 })
).subscribe(observer);
  • Related