rxjsobservablerxjs6rxjs-pipeable-operatorsretrywhen

rxjs 5.5+ retryWhen not calling source observable?


I feel like I'm missing something really simple here. I'm trying to create a simple retry for fetch but only the code in the retryWhen is getting executed. I'm using React so i dont have the this.http.get convenience. Perhaps it's an issue with from(/*promise*/)? I was trying to base the retry logic off of this post.

This is what I would expect to see:

Getting data from fetch...
In the retryWhen
In the interval
/* repeat the previous 3 lines 3x times including the Fetch */
Giving up

Instead I get:

Getting data from fetch...
In the retryWhen
In the interval...
In the interval...
In the interval...
In the interval...
Giving up

So it is just repeating the code in he retryWhen interval but not repeating the original fetchData call. I'm probably missing something fundamental to my RXJS knowledge.

Here's the test code:

const fetchData = new Promise((res, rej) => {
  console.log("Getting data from fetch...");
  rej(); // just fail immediately to test the retry
});

const source = from(fetchData)
  .pipe(
    retryWhen(_ => {
      console.log("In the retryWhen");
      return interval(1000).pipe(
        tap(_ => console.log("In the interval...")),
        flatMap(count => count == 3 ? throwError("Giving up") : of(count))
      )
    }));

source.subscribe(
  result => console.log(result),
  err => console.log(err)
);


Solution

  • Change to the code below see if it works. retryWhen pass you a error stream which will keep emitting if there is error. you return a timer to specify the delay in between each retry inside retryWhen. After the delay it will retry the source observable for you

    const fetchData = defer(() => new Promise((res, rej) => {
          console.log('in promise')
            rej("Failed to fetch data"); 
          // fail the first 2 times
        }) );
    
    const source = fetchData.pipe(
      retryWhen(err => {
        let count = 0;
        console.log("In the retryWhen");
        return err.pipe(
          tap(_ => {
            count++;
            console.log("In the interval...");
          }),
          mergeMap(_ => (count == 2 ? throwError("Giving up") : timer(2000)))
        );
      })
    );
    
    source.subscribe(result => console.log(result), err => console.warn(err));
    

    https://codepen.io/fancheung/pen/gqjawe