diff --git a/src/utils/queryCacher.ts b/src/utils/queryCacher.ts index f624bec0..5cb4fb37 100644 --- a/src/utils/queryCacher.ts +++ b/src/utils/queryCacher.ts @@ -149,6 +149,10 @@ function clearKey(key: string): void { redis.del(key).catch((err) => Logger.error(err)); } +function clearKeyPattern(keyPattern: string): void { + redis.delPattern(keyPattern).catch((err) => Logger.error(err)); +} + function clearSegmentCache(videoInfo: { videoID: VideoID; hashedVideoID: VideoIDHash; @@ -157,7 +161,7 @@ function clearSegmentCache(videoInfo: { }): void { if (videoInfo) { redis.del(skipSegmentsKey(videoInfo.videoID, videoInfo.service)).catch((err) => Logger.error(err)); - redis.del(skipSegmentGroupsKey(videoInfo.videoID, videoInfo.service)).catch((err) => Logger.error(err)); + clearKeyPattern(skipSegmentGroupsKey(videoInfo.videoID, "*", videoInfo.service)); redis.del(skipSegmentsHashKey(videoInfo.hashedVideoID, videoInfo.service)).catch((err) => Logger.error(err)); redis.del(videoLabelsKey(videoInfo.hashedVideoID, videoInfo.service)).catch((err) => Logger.error(err)); redis.del(videoLabelsHashKey(videoInfo.hashedVideoID, videoInfo.service)).catch((err) => Logger.error(err)); @@ -220,6 +224,7 @@ export const QueryCacher = { getTraced, getAndSplit, clearKey, + clearKeyPattern, clearSegmentCache, clearSegmentCacheByID, getKeyLastModified, diff --git a/src/utils/redis.ts b/src/utils/redis.ts index 05c1b999..9b221a13 100644 --- a/src/utils/redis.ts +++ b/src/utils/redis.ts @@ -1,13 +1,14 @@ -import { config } from "../config"; -import { Logger } from "./logger"; -import { RedisClientType, SetOptions, createClient } from "redis"; -import { RedisCommandArgument, RedisCommandArguments, RedisCommandRawReply } from "@redis/client/dist/lib/commands"; import { RedisClientOptions } from "@redis/client/dist/lib/client"; +import { RedisCommandArgument, RedisCommandArguments, RedisCommandRawReply } from "@redis/client/dist/lib/commands"; +import { ScanCommandOptions } from "@redis/client/dist/lib/commands/SCAN"; +import { LRUCache } from "lru-cache"; +import { compress, uncompress } from "lz4-napi"; import { RedisReply } from "rate-limit-redis"; +import { RedisClientType, SetOptions, createClient } from "redis"; +import { config } from "../config"; import { db } from "../databases/databases"; import { Postgres } from "../databases/Postgres"; -import { compress, uncompress } from "lz4-napi"; -import { LRUCache } from "lru-cache"; +import { Logger } from "./logger"; import { shouldClientCacheKey } from "./redisKeys"; export interface RedisStats { @@ -31,6 +32,7 @@ interface RedisSB { setEx(key: RedisCommandArgument, seconds: number, value: RedisCommandArgument): Promise; setExWithCache(key: RedisCommandArgument, seconds: number, value: RedisCommandArgument): Promise; del(...keys: [RedisCommandArgument]): Promise; + delPattern(pattern: RedisCommandArgument): Promise; increment?(key: RedisCommandArgument): Promise; sendCommand(args: RedisCommandArguments, options?: RedisClientOptions): Promise; ttl(key: RedisCommandArgument): Promise; @@ -45,6 +47,7 @@ let exportClient: RedisSB = { setEx: () => Promise.resolve(null), setExWithCache: () => Promise.resolve(null), del: () => Promise.resolve(null), + delPattern: () => Promise.resolve(null), increment: () => Promise.resolve(null), sendCommand: () => Promise.resolve(null), quit: () => Promise.resolve(null), @@ -199,6 +202,13 @@ if (config.redis?.enabled) { } }; + const scan = client.scan.bind(client); + exportClient.delPattern = async (pattern) => { + const keys = await scan(0, { MATCH: pattern } as ScanCommandOptions); + await Promise.allSettled(keys.keys.map((key) => exportClient.del(key))); + return keys.keys.length; + }; + const ttl = client.ttl.bind(client); exportClient.ttl = async (key) => { if (cache && cacheClient && ttlCache.has(key)) {