From 159d2e6bd1ffd872caa01ee6bebbb0edb81a17d1 Mon Sep 17 00:00:00 2001 From: "A.Vasilev" Date: Fri, 15 Jan 2021 18:48:05 +0300 Subject: [PATCH] fix(@cubejs-backend/query-orchestrator): prevent generic pool infinite loop --- .../src/orchestrator/RedisPool.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/cubejs-query-orchestrator/src/orchestrator/RedisPool.ts b/packages/cubejs-query-orchestrator/src/orchestrator/RedisPool.ts index ca7274ae7ee1b..4f898b9f13ff7 100644 --- a/packages/cubejs-query-orchestrator/src/orchestrator/RedisPool.ts +++ b/packages/cubejs-query-orchestrator/src/orchestrator/RedisPool.ts @@ -11,10 +11,14 @@ export interface RedisPoolOptions { destroyClient?: (client: AsyncRedisClient) => PromiseLike; } +const MAX_ALLOWED_POOL_ERRORS = 100; + export class RedisPool { protected readonly pool: Pool|null = null; protected readonly create: CreateRedisClientFn|null = null; + + protected poolErrors: number = 0; public constructor(options: RedisPoolOptions = {}) { const defaultMin = process.env.CUBEJS_REDIS_POOL_MIN ? parseInt(process.env.CUBEJS_REDIS_POOL_MIN, 10) : 2; @@ -29,13 +33,23 @@ export class RedisPool { idleTimeoutMillis: 5000, evictionRunIntervalMillis: 5000 }; - + const create = options.createClient || (async () => createRedisClient(process.env.REDIS_URL)); if (max > 0) { const destroy = options.destroyClient || (async (client) => client.end(true)); this.pool = genericPool.createPool({ create, destroy }, opts); + + this.pool.on('factoryCreateError', (error) => { + this.poolErrors++; + // prevent the infinite loop when pool creation fails too many times + if (this.poolErrors > MAX_ALLOWED_POOL_ERRORS) { + // @ts-ignore + // eslint-disable-next-line + this.pool._waitingClientsQueue.dequeue().reject(error); + } + }); } else { // fallback to un-pooled behavior if pool max is 0 this.create = create;