I am using NGRX and I want to have simple GET requests to an API to be retried five times. Reason for this is that I am using Azure Cosmos-DB and I am being throttled sometimes. (free-tier).
I've created an http-interceptor for this which is pretty straight forward and looks like that
@Injectable()
export class HttpRetryInterceptor implements HttpInterceptor {
public intercept(
request: HttpRequest<any>,
httpHandler: HttpHandler
): Observable<HttpEvent<any>> {
const nextRequest = request.clone();
// here the NGRX failure action is not being triggered after five failing requests
return httpHandler.handle(nextRequest).pipe(
retryWhen(errors => errors.pipe(delay(1000), take(5))),
last()
);
}
}
This works just fine and each failing http-request is retried five times with a delay of 1000ms.
Problem now is, that the failure action in the effect is not being triggered when the requests actually failed for five times.
load$ = createEffect(() =>
this.actions$.pipe(
ofType(globalStatsActions.load),
mergeMap(() =>
this.globalStatsService.load().pipe(
map(stats =>
globalStatsActions.loaded({
latestStats: stats
})
),
catchError(() => of(globalStatsActions.loadFailed())) // not being called using the http-interceptor
)
)
)
);
What is weird is, that when the http-interceptor uses the operator retry rather than retryWhen it works just fine. Sadly, with that operator you cannot define a delay, which is required in my case.
Another interesting fact is, that when using the very same retry logic on the service used in the effect, it works just fine.
// here the failure action is being triggered after five failing requests
public load(): Observable<GlobalStats> {
return this.http.get<GlobalStats>(`${this.baseUrl}stats`)
.pipe(
retryWhen(errors => errors.pipe(delay(1000), take(5))),
last()
);
While this is not much code and could be copied onto each http-service that I am using, I would love to use an interceptor for it instead.
I couldn't seem to find the cause for that and I hope, that anyone out there knows why this is not working.