Created
February 13, 2023 12:43
-
-
Save Artawower/3bb46acbc3a8364c084599e81271e94d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse } from '@angular/common/http'; | |
import { Injectable } from '@angular/core'; | |
import { Observable, of, timer } from 'rxjs'; | |
import { mergeMap, tap, retryWhen, delayWhen } from 'rxjs/operators'; | |
@Injectable() | |
/** | |
* This class is used to intercept network errors with status 500+ and some 400s | |
* then add failed request to the queue and try to resend it after | |
* some times. | |
*/ | |
export class RetryInterceptor implements HttpInterceptor { | |
private readonly INITIAL_RETRY_DELAY = 5000; // 5 seconds | |
private readonly MAX_RETRY_DELAY = 15000; // 15 seconds | |
private readonly httpRequestsWithError: { [key: string]: number } = {}; | |
private readonly retryStatusCodes = [0, 408, 429, 449, 425, 410, 405]; | |
constructor() {} | |
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { | |
return next.handle(req).pipe( | |
retryWhen((errors) => | |
errors.pipe( | |
mergeMap((error: HttpResponse<any>) => { | |
console.log('✎: [line 28][retry.interceptor.ts] error: ', error); | |
if (this.isRetryableRequest(error.status)) { | |
this.increaseRetryDelay(req); | |
return of(error); | |
} | |
this.clearRetryState(req); | |
throw error; | |
}), | |
delayWhen(() => timer(this.getRetryDelay(req))) | |
) | |
), | |
tap(() => { | |
this.clearRetryState(req); | |
}) | |
); | |
} | |
private isRetryableRequest(status: number): boolean { | |
return status >= 500 || this.retryStatusCodes.includes(status); | |
} | |
private increaseRetryDelay(req: HttpRequest<any>): void { | |
const requestKey = this.getUniqueRequestMethod(req); | |
if (!this.httpRequestsWithError[requestKey]) { | |
this.httpRequestsWithError[requestKey] = 0; | |
} | |
this.httpRequestsWithError[requestKey] += 1; | |
} | |
private getUniqueRequestMethod(req: HttpRequest<any>): string { | |
return `${req.method}_${req.urlWithParams}`; | |
} | |
private getRetryDelay(req: HttpRequest<any>): number { | |
const requestKey = this.getUniqueRequestMethod(req); | |
const failedCount = this.httpRequestsWithError[requestKey]; | |
const retryDelay = this.INITIAL_RETRY_DELAY * failedCount; | |
return Math.min(retryDelay, this.MAX_RETRY_DELAY); | |
} | |
private clearRetryState(req: HttpRequest<any>): void { | |
const requestKey = this.getUniqueRequestMethod(req); | |
delete this.httpRequestsWithError[requestKey]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment