53 lines
2.0 KiB
TypeScript
53 lines
2.0 KiB
TypeScript
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
|
import { Inject, Injectable, Optional } from '@angular/core';
|
|
import { MonoTypeOperatorFunction, Observable, throwError, timer } from 'rxjs';
|
|
import { catchError, mergeMap, retryWhen, tap } from 'rxjs/operators';
|
|
import { MAX_RETRIES_ON_SERVER_ERROR } from './max-retries.token';
|
|
import { ErrorService } from './error.service';
|
|
|
|
function updateSeconds(seconds: number) {
|
|
if (seconds === 0 || seconds === 1) {
|
|
return seconds + 1;
|
|
} else {
|
|
return seconds * seconds;
|
|
}
|
|
}
|
|
|
|
function backoffOnServerError(maxRetries = 3): MonoTypeOperatorFunction<HttpEvent<unknown>> {
|
|
let seconds = 0;
|
|
return retryWhen(attempts =>
|
|
attempts.pipe(
|
|
tap(() => (seconds = updateSeconds(seconds))),
|
|
mergeMap((error: HttpErrorResponse, index) => {
|
|
if ((error.status < 500 && error.status !== 0) || index === maxRetries) {
|
|
return throwError(error);
|
|
} else {
|
|
console.error('An error occurred: ', error);
|
|
console.error(`Retrying in ${seconds} seconds...`);
|
|
return timer(seconds * 1000);
|
|
}
|
|
}),
|
|
),
|
|
);
|
|
}
|
|
|
|
@Injectable()
|
|
export class ServerErrorInterceptor implements HttpInterceptor {
|
|
constructor(
|
|
private readonly _errorService: ErrorService,
|
|
@Optional() @Inject(MAX_RETRIES_ON_SERVER_ERROR) private readonly _maxRetries: number,
|
|
) {}
|
|
|
|
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
|
return next.handle(req).pipe(
|
|
catchError((error: HttpErrorResponse) => {
|
|
if (error.status >= 500 || error.status === 0) {
|
|
this._errorService.set(error);
|
|
}
|
|
return throwError(error);
|
|
}),
|
|
backoffOnServerError(this._maxRetries || 3),
|
|
);
|
|
}
|
|
}
|