refactor: v2 throttler guard (#16922)

* chore: add logs

* refactor: replace deprecated redis.setex with redis.set

* chore: log response headers
This commit is contained in:
Lauris Skraucis
2024-10-07 11:02:41 +00:00
committed by GitHub
parent d8eb1df61d
commit 44f6f2e320
+30 -4
View File
@@ -51,6 +51,11 @@ export class CustomThrottlerGuard extends ThrottlerGuard {
const request = context.switchToHttp().getRequest<Request>();
const response = context.switchToHttp().getResponse<Response>();
const tracker = await this.getTracker(request);
this.logger.log(
`Tracker "${tracker}" generated based on: Bearer token "${request.get(
"Authorization"
)}", OAuth client ID "${request.get(X_CAL_CLIENT_ID)}" and IP "${request.ip}"`
);
if (tracker.startsWith("api_key_")) {
return this.handleApiKeyRequest(tracker, response);
@@ -79,6 +84,9 @@ export class CustomThrottlerGuard extends ThrottlerGuard {
private async handleNonApiKeyRequest(tracker: string, response: Response): Promise<boolean> {
const rateLimit = this.getDefaultRateLimit();
this.logger.log(`Tracker "${tracker}" uses default rate limits because it is not tracking api key:
${JSON.stringify(rateLimit, null, 2)}
`);
const { isBlocked } = await this.incrementRateLimit(tracker, rateLimit, response);
if (isBlocked) {
@@ -114,6 +122,9 @@ export class CustomThrottlerGuard extends ThrottlerGuard {
const cachedRateLimits = await this.storageService.redis.get(cacheKey);
if (cachedRateLimits) {
this.logger.log(`Tracker "${tracker}" rate limits retrieved from redis cache:
${cachedRateLimits}
`);
return rateLimitsSchema.parse(JSON.parse(cachedRateLimits));
}
@@ -133,11 +144,18 @@ export class CustomThrottlerGuard extends ThrottlerGuard {
select: { name: true, limit: true, ttl: true, blockDuration: true },
});
if (!rateLimits || rateLimits.length === 0) {
rateLimits = [this.getDefaultRateLimit()];
if (rateLimits) {
this.logger.log(`Tracker "${tracker}" rate limits retrieved from database:
${JSON.stringify(rateLimits, null, 2)}`);
}
await this.storageService.redis.setex(cacheKey, 3600, JSON.stringify(rateLimits));
if (!rateLimits || rateLimits.length === 0) {
rateLimits = [this.getDefaultRateLimit()];
this.logger.log(`Tracker "${tracker}" rate limits not found in database. Using default rate limits:
${JSON.stringify(rateLimits, null, 2)}`);
}
await this.storageService.redis.set(cacheKey, JSON.stringify(rateLimits), "EX", 3600);
return rateLimits;
}
@@ -163,7 +181,15 @@ export class CustomThrottlerGuard extends ThrottlerGuard {
);
response.setHeader(`X-RateLimit-Reset-${nameFirstUpper}`, timeToBlockExpire || timeToExpire);
this.logger.log(`Rate limit for ${tracker} incremented. Remaining: ${limit - totalHits}`);
this.logger.log(
`Tracker "${tracker}" rate limit "${name}" incremented. isBlocked ${isBlocked}, totalHits ${totalHits}, timeToExpire ${timeToExpire}, timeToBlockExpire ${timeToBlockExpire}`
);
this.logger.log(
`Tracker "${tracker}" rate limit "${name}" response headers:
X-RateLimit-Limit-${nameFirstUpper}: ${limit},
X-RateLimit-Remaining-${nameFirstUpper}: ${timeToBlockExpire ? 0 : Math.max(0, limit - totalHits)},
X-RateLimit-Reset-${nameFirstUpper}: ${timeToBlockExpire || timeToExpire}`
);
return { isBlocked };
}