diff --git a/shared-code/src/data-access-layer/data-access-objects/data-access-object-redis.ts b/shared-code/src/data-access-layer/data-access-objects/data-access-object-redis.ts index f1b6e4b5..498e3792 100644 --- a/shared-code/src/data-access-layer/data-access-objects/data-access-object-redis.ts +++ b/shared-code/src/data-access-layer/data-access-objects/data-access-object-redis.ts @@ -815,7 +815,7 @@ export class DataAccessObjectRedis extends BasicDataAccessObject implements IDat public async getTablesFromDB(): Promise> { const redisClient = await this.getClient(); - const allKeys = await redisClient.keys('*'); + const allKeys = await this.getAllKeysWithTimeout(redisClient); const prefixedTableNames = new Set(); const standaloneKeys: Array<{ key: string; type: string }> = []; @@ -833,7 +833,7 @@ export class DataAccessObjectRedis extends BasicDataAccessObject implements IDat continue; } } - } + } const tables: Array = []; @@ -1634,4 +1634,37 @@ export class DataAccessObjectRedis extends BasicDataAccessObject implements IDat } }); } + + private async getAllKeysWithScan(redisClient: RedisClientType, pattern: string = '*'): Promise { + const allKeys: string[] = []; + const scanOptions = { MATCH: pattern, COUNT: 1000 }; + let cursor = '0'; + + do { + const result = await redisClient.scan(cursor, scanOptions); + cursor = result.cursor.toString(); + allKeys.push(...result.keys); + } while (cursor !== '0'); + + return allKeys; + } + + private async getAllKeysWithTimeout( + redisClient: RedisClientType, + timeoutMs: number = 5000, + ): Promise { + const keysPromise = redisClient.keys('*'); + + const timeoutPromise = new Promise((resolve) => { + setTimeout(() => resolve(null), timeoutMs); + }); + + const result = await Promise.race([keysPromise, timeoutPromise]); + + if (result === null) { + return this.getAllKeysWithScan(redisClient); + } + + return result; + } }