Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 1x 1x 7x 9x 8x 8x 6x 6x 6x 6x 2x 2x 2x 1x | import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, retry, timer } from 'rxjs';
@Injectable()
export class RateLimitInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(
retry({
count: 3,
delay: (error: HttpErrorResponse, retryCount: number) => {
// Check if status code is 503 (Service Unavailable) or 429 (Too Many Requests)
if (error.status === 503 || error.status === 429) {
// Try to read X-RateLimit-Retry-After header
const retryAfterHeader = error.headers?.get('X-RateLimit-Retry-After');
if (retryAfterHeader) {
// Parse the header value - it should be in seconds (can be decimal like 3.5)
const retryAfterSeconds = parseFloat(retryAfterHeader);
Eif (!isNaN(retryAfterSeconds) && retryAfterSeconds > 0) {
console.warn(`Rate limit hit. Retrying after ${retryAfterSeconds} seconds`);
// Convert seconds to milliseconds for timer
return timer(retryAfterSeconds * 1000);
}
}
// If no valid header, use exponential backoff (1s, 2s, 4s)
const backoffDelay = Math.pow(2, retryCount - 1) * 1000;
console.warn(`Rate limit hit. Retrying with exponential backoff: ${backoffDelay}ms`);
return timer(backoffDelay);
}
// For other errors, don't retry
throw error;
},
})
);
}
}
|