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);
});
})
}
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:
getImagesFromMovieDB()
is actually important - it needs to return a unique observable for every call for this to work, please ensure this is the case. I simulated this in the StackBlitz by constructing the Observable return with delay
..subscribe()
to print out the total elapsed time taken to get valid data for this res.status
. I did this only to show for each emission that it correctly takes the sum of all delays.
It is retried after every failure for a random amount of time (I arbitrarily chose between 5 and 10 seconds), as returned by the response header in your original function.return of("error")
but the first is unnecessary since the second will be immediately executed, so I commented that one out.I hope this helps.