How do I throw an exception after exhausting RxJs retryWhen operator attempts?

Viewed 231

I want to catch the exception in subscribe but the result is not being as expected.

this.userService.isUsernameValid (username)
      .pipe (
          catchError (err =>
          {
            return throwError (err);
          }),
          retryWhen (errors =>
              errors.pipe (
                  delay (2500),
                  take (4),
                  concatMap (() => throwError ('Network error'))
              )
          )
       )
      .subscribe (
          data =>
          {
            //
          },
          error =>
          {
            console.log (error)
          });

I would like the exception to be thrown only if all attempts fail.

The code above only makes the first request and in case of an error throws the exception (does not redo the request).

If I remove the concatMap the 4 attempts will be made but I will not be able to catch the error within the subscribe if none is successful.

Thanks in advance.

2 Answers

You can rethrow the error yourself under certain condition. For example concatMap passes index parameter to its projection function you can use instead of take():

throwError("It's broken")
  .pipe(
    retryWhen(errors => errors.pipe(
      concatMap((e, index) => index === 4 ? throwError(e) : of(null)),
    )),
  )
  .subscribe({
    next: x => console.log(x),
    error: e => console.log('obs', e),
  });

Live demo: https://stackblitz.com/edit/rxjs-kyr8zp

Adding to martin's solution:

The code above only makes the first request and in case of an error throws the exception (does not redo the request).

retryWhen(fn) maintains an inner subscription for the observable resulted from calling the provided function fn. The retryWhen's source will be re-subscribed only when the inner observable emits a value.

In your case, due to second throwError(), it will emit an error notification, so what retryWhen does in this is case is to pass along the error notification do the destination subscriber, which basically means that the error callback will be invoked and the whole stream will be unsubscribed.

If I remove the concatMap the 4 attempts will be made but I will not be able to catch the error within the subscribe if none is successful.

This is because when 4 attempts are reached, the inner observable will complete, meaning that there is no way it will emit a value again. Remember that when it emits a value, the source is re-subscribed.

Related