Skip to content

Feature: Emit something before retry. #6645

@benlesh

Description

@benlesh

Issue this would address:

Frequently I find myself writing code to dance around the fact that I want to do things like display the number of retry attempts as I'm retrying. Currently, I've just been using a side effect to do that, but it would be nice if I could output the retry attempts or a retry message in to the same output stream.

const retryInfo = new Subject<{ count: number, error: any }>();

source$.pipe(
  retry({
    delay: (error, count) => {
       // log the error so we can see it.
       console.error(error);
       
       // Notify some external observer that there's a retry in progress
       retryInfo.next({ count, error });
       
       // delay the retry by some time
       return timer(5000);
    }
  })
)

The problem with this approach is I've found it's better to mix connection status, or upload progress, or whatever, into the same stream as the output data, and share/filter it appropriately later.

Proposed solution:

Add a configurable/optional function that can be used to select a temporary observable that will be run until the retry commences. This can also be used for synchronous retry. In this case I'm calling it emitOnRetry, but we can bikeshed that name.

declare const source$: Observable<{ type: 'CONNECTING' | 'CONNECTED' | 'UPDATE', payload?: SomeData[]>;

source$.pipe(
  retry({
    emitOnRetry: (error, count) => of({ type: 'RETRY', error, count }),
    delay: (error, count) => {
       // log the error so we can see it.
       console.error(error);
       
       // delay the retry by some time
       return timer(5000);
    }
  })
)

The behavior of the above:

  1. When source$ errors, call emitOnRetry, and immediately subscribe to the resulting observable input, flattening results into the resulting observable
  2. Then immediately call and subscribe to the result of delay.
  3. When the result of delay emits, immediately unsubscribe from the emitOnRetry observable and execute appropriate retry logic.

In the synchronous retry case (when delay is not provided), this wouldn't work any different. If emitOnRetry returned a synchronous source, it would have a chance to emit whatever it was before the sync retry logic fired.

Pros

  • This would be a powerful feature to add to the new retry, which is already an improvement over retryWhen and the previous retry.
  • The only other way to accomplish this with existing operators before would have been with something like catchError then repeat, but that would not have allowed for access to the retry count.

Cons

  • Added surface area may create some additional confusion. Especially around sync retries?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions