node.jstypescriptrxjsdelayretrywhen

set delay dynamic on retryWhen


Is it possible to set the delay value dynamic after every retry. I tried it like this but it looks lite it keeps the value which is set initial.

imageController(epgData: EpgDataDTO[], showOrMovie: string){
    var retryAfterMilliSeconds = 1000;
    epgData.forEach( (data) => {
        this.getImagesFromMovieDB(data.title).pipe(
            retryWhen((error) => {
                return error.pipe(
                    mergeMap((error: any) => {
                            if(error.response.status === 429) {
                                const retryAfter = error.response.headers;
                                retryAfterMilliSeconds = +retryAfter['retry-after'] * 1000
                                console.log(retryAfterMilliSeconds); // it tells me the correct value here but the retry happens every 1000ms
                                console.log(data.title);
                            }else{
                                this.errorHandling(error)
                                return of("error");
                            }
                            return of("error");
                        }),
                    delay(retryAfterMilliSeconds),
                    take(5)
                )
        }))
        .subscribe( (res) => {
            console.log(res.status);
            console.log(res.headers);

        });
    })
}

Solution

  • You were VERY close! To get this to work, all I had to do was move the delay(retryAfterMilliSeconds) to after the return value of the mergeMap() operator to tie it to the same observable. Without this it would randomly delay the RETURN from mergeMap() which would be random for which Observable was actually delayed.

    I put this up in a Stackblitz to test it. Click on 'Console' at the bottom of the far right frame to see results.

    Here is the function from that StackBlitz:

    imageController(epgData: EpgDataDTO[], showOrMovie: string){
        var retryAfterMilliSeconds = 1000;
        epgData.forEach( (data) => {
            this.getImagesFromMovieDB(data.title).pipe(
                retryWhen((error) => {
                    return error.pipe(
                        mergeMap((error: any) => {
                                if(error.response.status === 429) {
                                    const retryAfter = error.response.headers;
                                    retryAfterMilliSeconds = +retryAfter['retry-after'] * 1000
                                    console.log(retryAfterMilliSeconds); // it tells me the correct value here but the retry happens every 1000ms
                                    console.log(data.title);
                                }else{
                                    this.errorHandling(error)
                                    // return of("error"); <-- unnecessary since this will be executed with next statement
                                }
                                return of("error").pipe(delay(retryAfterMilliSeconds));
                            }),
                        // delay(retryAfterMilliSeconds),
                        take(5)
                    )
            }))
            .subscribe( 
                (res) => {
                    // console.log(res.status);
                    // console.log(res.headers);
                    const elapsedTime = Math.round(((new Date()).getTime() - startTime) / 1000);
                    console.log(`'${res.status}' is Ok - total elapsed time ${elapsedTime} seconds`);
                }
            );
        })
    }
    

    Some other notes:

    I hope this helps.