diff --git a/apps/redis-api/src/index.ts b/apps/redis-api/src/index.ts index ce85ca2e4..6583ecf4e 100644 --- a/apps/redis-api/src/index.ts +++ b/apps/redis-api/src/index.ts @@ -11,6 +11,10 @@ import serverTiming from "@elysiajs/server-timing"; import { AuthenticationError } from "@/errors/AuthenticationError"; import { ModelValidationError } from "@/errors/ModelValidationError"; +import { setupShutdown } from "@/shutdown"; + +setupShutdown(); + const app = new Elysia() .use(serverTiming()) .error("AUTHENTICATION_ERROR", AuthenticationError) diff --git a/apps/redis-api/src/routes/api/cache.ts b/apps/redis-api/src/routes/api/cache.ts index a74a46940..f32a445de 100644 --- a/apps/redis-api/src/routes/api/cache.ts +++ b/apps/redis-api/src/routes/api/cache.ts @@ -5,6 +5,7 @@ import { redis } from "@/services/redis"; import { ModelValidationError } from "@/errors/ModelValidationError"; import { loggerModule } from "@/utils/logger"; import { truncate } from "@/utils/truncate"; +import { timeout } from "@/utils/timeout"; const MIN_LENGTH = 1; @@ -92,10 +93,13 @@ function validateKey(key: string) { if (parsedKey.length < MIN_LENGTH) { throw new ModelValidationError( - "Key has to be atleast 1 character long" + "Key has to be at least 1 character long" ); } + if (parsedKey.includes("*")) { + throw new ModelValidationError("Key cannot contain wildcards"); + } if (parsedKey.includes("*")) { throw new ModelValidationError("Key cannot contain wildcards"); } @@ -115,6 +119,10 @@ async function deleteWithPattern(pattern: string) { "COUNT", 5000 ); + + // Throttle calls to Redis to avoid overwhelming it + await timeout(50); + cursor = newCursor; keys.push(...foundKeys); } while (cursor !== "0"); diff --git a/apps/redis-api/src/shutdown.ts b/apps/redis-api/src/shutdown.ts new file mode 100644 index 000000000..9f9bbcd3e --- /dev/null +++ b/apps/redis-api/src/shutdown.ts @@ -0,0 +1,16 @@ +import { loggerModule } from "@/utils/logger"; +import { redis } from "@/services/redis"; + +const shutdownLogger = loggerModule("shutdown"); + +export function setupShutdown() { + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); +} + +async function shutdown() { + shutdownLogger.info("Shutting down..."); + shutdownLogger.info("Closing Redis connection..."); + await redis.quit(); + process.exit(0); +} diff --git a/apps/redis-api/src/utils/timeout.ts b/apps/redis-api/src/utils/timeout.ts new file mode 100644 index 000000000..e6c99d779 --- /dev/null +++ b/apps/redis-api/src/utils/timeout.ts @@ -0,0 +1,3 @@ +export function timeout(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +}