I am trying to create a retry config for retry after catchError. I need to send specific delays based on values in an array. I want to be able to take each value from the array and send them individually to a timer creation function.
so for example:
numberArr = [1000, 2000, 3000]
timer is called with timer(1000), then timer(2000), then timer(3000)
using concatMap only uses the first value, switchMap the last, but I am unsure of what to use to take each emitted number and use that value for the timer function.
Any suggestions would be welcome.
private ob$ = of(1);
private retryConfig: {
matcher: () => void;
retryWaits: number[];
};
constructor() {}
private setRetryConfig(): RetryConfig {
this.retryConfig = {
matcher: () => {},
retryWaits: [3000, 4000, 6000],
};
const delayObservable$ = from(this.retryConfig.retryWaits)
const delayFunction = delayObservable$.pipe(
tap(() => console.time()),
tap((x) => console.log('delay', x)),
concatMap((number) => timer(number)), // this is where I am seeing a problem
take(this.retryConfig.retryWaits.length),
tap(() => console.timeEnd()) // this is alway logging 3000ish milliseconds
);
return {
count: this.retryConfig.retryWaits.length,
delay: () => delayFunction,
};
}
ngOnInit(): void {
this.ob$
.pipe(
tap(() => {
throw throwError(() => new Error('error'));
}),
catchError((error) => throwError(() => new Error(error))),
retry(this.setRetryConfig())
)
.subscribe((x) => {
if (x) {
throw throwError(() => new Error('error'));
}
});
}
CodePudding user response:
The delay
function gets called everytime the error is thrown. We can't use the array of numbers to wait x times. Instead, we need to use whatever the current retry-wait value is and wait once.
We can achieve this by calling timer
in the delay
callback and passing it the first element of retryWaits
simultaneously removing it from the array.
const setRetryConfig = () => {
const retryConfig = {
matcher: () => {},
retryWaits: [3000, 4000, 6000],
};
return {
count: retryConfig.retryWaits.length,
delay: () => timer(retryConfig.retryWaits.shift())
}
}
Also note that throwing an Error
inside a tap
might not work. I threw the error in a mergeMap
instead.
of(0).pipe(
mergeMap(() => {
console.log("trying")
return throwError(() => 'Error!');
}),
retry(setRetryConfig())
).subscribe(r => console.log("Result", r))
This outputs:
trying
---0s---
---1s---
---2s---
trying
---3s---
---4s---
---5s---
---6s---
---7s---
trying
---8s---
---9s---
---10s---
---11s---
---12s---
---13s---
---14s---
trying
---15s---
Error!