Merged in feat/redis-batch-delete (pull request #2170)

feat: redis - batch delete in smaller chunks

* feat: redis - batch delete in smaller chunks

* fix: redis-api remove unnecessary loop when fuzzily deleting

* increase timeout between delete batches


Approved-by: Joakim Jäderberg
This commit is contained in:
Linus Flood
2025-05-21 11:16:35 +00:00
committed by Joakim Jäderberg
parent e6ed94029e
commit 16be305ad3

View File

@@ -67,34 +67,27 @@ export const cacheRoutes = new Elysia({ prefix: "/cache" })
) )
.delete( .delete(
"/", "/",
async ({ query: { key, fuzzy }, set }) => { async ({ query: { key, fuzzy } }) => {
key = validateKey(key); key = validateKey(key);
cacheRouteLogger.info( cacheRouteLogger.info(
`DELETE /cache ${key} ${fuzzy ? "fuzzy" : ""}` `DELETE /cache ${key} ${fuzzy ? "fuzzy" : ""}`
); );
const deletedKeys: number = fuzzy
? await deleteWithPattern(`*${key}*`)
: await redis.del(key);
if (fuzzy) { cacheRouteLogger.info(`Deleted ${deletedKeys} keys for '${key}'`);
await deleteWithPattern(`*${key}*`); return { deletedKeys };
} else {
const deletedKeys = await redis.del(key);
if (deletedKeys === 0) {
cacheRouteLogger.info(
`Key '${key}' not found, nothing deleted`
);
} else {
cacheRouteLogger.info(`Deleted key '${key}'`);
}
}
set.status = 204;
return undefined;
}, },
{ {
query: t.Object({ query: t.Object({
...QUERY_TYPE.properties, ...QUERY_TYPE.properties,
...t.Object({ fuzzy: t.Optional(t.Boolean()) }).properties, ...t.Object({ fuzzy: t.Optional(t.Boolean()) }).properties,
}), }),
response: { 204: t.Undefined(), 400: t.String() }, response: {
200: t.Object({ deletedKeys: t.Number() }),
400: t.String(),
},
} }
); );
@@ -116,7 +109,9 @@ function validateKey(key: string) {
async function deleteWithPattern(pattern: string) { async function deleteWithPattern(pattern: string) {
let cursor = "0"; let cursor = "0";
const keys: string[] = []; const SCAN_SIZE = 500;
let totalDeleteCount = 0;
do { do {
const [newCursor, foundKeys] = await redis.scan( const [newCursor, foundKeys] = await redis.scan(
@@ -124,24 +119,21 @@ async function deleteWithPattern(pattern: string) {
"MATCH", "MATCH",
pattern, pattern,
"COUNT", "COUNT",
5000 SCAN_SIZE
); );
// Throttle calls to Redis to avoid overwhelming it
await timeout(50);
cursor = newCursor; cursor = newCursor;
keys.push(...foundKeys); if (foundKeys.length === 0) {
continue;
}
const deleteCount = await redis.del(foundKeys);
cacheRouteLogger.info(`Deleted ${deleteCount} keys in this batch.`);
totalDeleteCount += deleteCount;
await timeout(10);
} while (cursor !== "0"); } while (cursor !== "0");
if (keys.length > 0) { return totalDeleteCount;
const deleteCount = await redis.del(...keys);
keys.map((key, idx) => {
cacheRouteLogger.info(
`Deleted key ${idx + 1}/${deleteCount}: ${key}`
);
});
cacheRouteLogger.info(`Deleted number of keys: ${deleteCount}`);
}
} }