mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-02 08:46:38 +00:00
Clean up old timestamps
This commit is contained in:
@@ -72,6 +72,38 @@ export class RateLimitService {
|
|||||||
return `ratelimit:${clientId}:${messageType}`;
|
return `ratelimit:${clientId}:${messageType}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to clean up old timestamp fields from a Redis hash
|
||||||
|
private async cleanupOldTimestamps(key: string, windowStart: number): Promise<void> {
|
||||||
|
if (!redisManager.isRedisEnabled()) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const client = redisManager.getClient();
|
||||||
|
if (!client) return;
|
||||||
|
|
||||||
|
// Get all fields in the hash
|
||||||
|
const allData = await redisManager.hgetall(key);
|
||||||
|
if (!allData || Object.keys(allData).length === 0) return;
|
||||||
|
|
||||||
|
// Find fields that are older than the window
|
||||||
|
const fieldsToDelete: string[] = [];
|
||||||
|
for (const timestamp of Object.keys(allData)) {
|
||||||
|
const time = parseInt(timestamp);
|
||||||
|
if (time < windowStart) {
|
||||||
|
fieldsToDelete.push(timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete old fields in batch
|
||||||
|
if (fieldsToDelete.length > 0) {
|
||||||
|
await client.hdel(key, ...fieldsToDelete);
|
||||||
|
logger.debug(`Cleaned up ${fieldsToDelete.length} old timestamp fields from ${key}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Failed to cleanup old timestamps for key ${key}:`, error);
|
||||||
|
// Don't throw - cleanup failures shouldn't block rate limiting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to sync local rate limit data to Redis
|
// Helper function to sync local rate limit data to Redis
|
||||||
private async syncRateLimitToRedis(
|
private async syncRateLimitToRedis(
|
||||||
clientId: string,
|
clientId: string,
|
||||||
@@ -81,8 +113,12 @@ export class RateLimitService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const currentTime = Math.floor(Date.now() / 1000);
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
|
const windowStart = currentTime - RATE_LIMIT_WINDOW;
|
||||||
const globalKey = this.getRateLimitKey(clientId);
|
const globalKey = this.getRateLimitKey(clientId);
|
||||||
|
|
||||||
|
// Clean up old timestamp fields before writing
|
||||||
|
await this.cleanupOldTimestamps(globalKey, windowStart);
|
||||||
|
|
||||||
// Get current value and add pending count
|
// Get current value and add pending count
|
||||||
const currentValue = await redisManager.hget(
|
const currentValue = await redisManager.hget(
|
||||||
globalKey,
|
globalKey,
|
||||||
@@ -93,7 +129,7 @@ export class RateLimitService {
|
|||||||
).toString();
|
).toString();
|
||||||
await redisManager.hset(globalKey, currentTime.toString(), newValue);
|
await redisManager.hset(globalKey, currentTime.toString(), newValue);
|
||||||
|
|
||||||
// Set TTL using the client directly
|
// Set TTL using the client directly - this prevents the key from persisting forever
|
||||||
if (redisManager.getClient()) {
|
if (redisManager.getClient()) {
|
||||||
await redisManager
|
await redisManager
|
||||||
.getClient()
|
.getClient()
|
||||||
@@ -119,8 +155,12 @@ export class RateLimitService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const currentTime = Math.floor(Date.now() / 1000);
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
|
const windowStart = currentTime - RATE_LIMIT_WINDOW;
|
||||||
const messageTypeKey = this.getMessageTypeRateLimitKey(clientId, messageType);
|
const messageTypeKey = this.getMessageTypeRateLimitKey(clientId, messageType);
|
||||||
|
|
||||||
|
// Clean up old timestamp fields before writing
|
||||||
|
await this.cleanupOldTimestamps(messageTypeKey, windowStart);
|
||||||
|
|
||||||
// Get current value and add pending count
|
// Get current value and add pending count
|
||||||
const currentValue = await redisManager.hget(
|
const currentValue = await redisManager.hget(
|
||||||
messageTypeKey,
|
messageTypeKey,
|
||||||
@@ -135,7 +175,7 @@ export class RateLimitService {
|
|||||||
newValue
|
newValue
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set TTL using the client directly
|
// Set TTL using the client directly - this prevents the key from persisting forever
|
||||||
if (redisManager.getClient()) {
|
if (redisManager.getClient()) {
|
||||||
await redisManager
|
await redisManager
|
||||||
.getClient()
|
.getClient()
|
||||||
@@ -170,6 +210,10 @@ export class RateLimitService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const globalKey = this.getRateLimitKey(clientId);
|
const globalKey = this.getRateLimitKey(clientId);
|
||||||
|
|
||||||
|
// Clean up old timestamp fields before reading
|
||||||
|
await this.cleanupOldTimestamps(globalKey, windowStart);
|
||||||
|
|
||||||
const globalRateLimitData = await redisManager.hgetall(globalKey);
|
const globalRateLimitData = await redisManager.hgetall(globalKey);
|
||||||
|
|
||||||
let count = 0;
|
let count = 0;
|
||||||
@@ -215,6 +259,10 @@ export class RateLimitService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const messageTypeKey = this.getMessageTypeRateLimitKey(clientId, messageType);
|
const messageTypeKey = this.getMessageTypeRateLimitKey(clientId, messageType);
|
||||||
|
|
||||||
|
// Clean up old timestamp fields before reading
|
||||||
|
await this.cleanupOldTimestamps(messageTypeKey, windowStart);
|
||||||
|
|
||||||
const messageTypeRateLimitData = await redisManager.hgetall(messageTypeKey);
|
const messageTypeRateLimitData = await redisManager.hgetall(messageTypeKey);
|
||||||
|
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user