From 52512463132bfd5daf5c78a020e134dc395db7a9 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Fri, 25 Jul 2025 12:33:05 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=B1=20refactor:=20Redis=20Client=20Err?= =?UTF-8?q?or=20Logging=20and=20Ping=20only=20when=20Ready=20(#8671)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 📱 refactor: Redis Client Error Logging and Ping only when Ready * chore: intellisense for warning comment for Keyv Redis client regarding prefix support --- api/cache/redisClients.js | 58 +++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/api/cache/redisClients.js b/api/cache/redisClients.js index 5a633b196b..46c2813e95 100644 --- a/api/cache/redisClients.js +++ b/api/cache/redisClients.js @@ -1,6 +1,7 @@ const IoRedis = require('ioredis'); -const { cacheConfig } = require('./cacheConfig'); +const { logger } = require('@librechat/data-schemas'); const { createClient, createCluster } = require('@keyv/redis'); +const { cacheConfig } = require('./cacheConfig'); const GLOBAL_PREFIX_SEPARATOR = '::'; @@ -25,20 +26,37 @@ if (cacheConfig.USE_REDIS) { ? new IoRedis(cacheConfig.REDIS_URI, redisOptions) : new IoRedis.Cluster(cacheConfig.REDIS_URI, { redisOptions }); - // Pinging the Redis server to keep the connection alive (if enabled) + ioredisClient.on('error', (err) => { + logger.error('ioredis client error:', err); + }); + + /** Ping Interval to keep the Redis server connection alive (if enabled) */ let pingInterval = null; + const clearPingInterval = () => { + if (pingInterval) { + clearInterval(pingInterval); + pingInterval = null; + } + }; + if (cacheConfig.REDIS_PING_INTERVAL > 0) { - pingInterval = setInterval(() => ioredisClient.ping(), cacheConfig.REDIS_PING_INTERVAL * 1000); - ioredisClient.on('close', () => clearInterval(pingInterval)); - ioredisClient.on('end', () => clearInterval(pingInterval)); + pingInterval = setInterval(() => { + if (ioredisClient && ioredisClient.status === 'ready') { + ioredisClient.ping(); + } + }, cacheConfig.REDIS_PING_INTERVAL * 1000); + ioredisClient.on('close', clearPingInterval); + ioredisClient.on('end', clearPingInterval); } } /** @type {import('@keyv/redis').RedisClient | import('@keyv/redis').RedisCluster | null} */ let keyvRedisClient = null; if (cacheConfig.USE_REDIS) { - // ** WARNING ** Keyv Redis client does not support Prefix like ioredis above. - // The prefix feature will be handled by the Keyv-Redis store in cacheFactory.js + /** + * ** WARNING ** Keyv Redis client does not support Prefix like ioredis above. + * The prefix feature will be handled by the Keyv-Redis store in cacheFactory.js + */ const redisOptions = { username, password, socket: { tls: ca != null, ca } }; keyvRedisClient = @@ -51,15 +69,27 @@ if (cacheConfig.USE_REDIS) { keyvRedisClient.setMaxListeners(cacheConfig.REDIS_MAX_LISTENERS); - // Pinging the Redis server to keep the connection alive (if enabled) + keyvRedisClient.on('error', (err) => { + logger.error('@keyv/redis client error:', err); + }); + + /** Ping Interval to keep the Redis server connection alive (if enabled) */ let pingInterval = null; + const clearPingInterval = () => { + if (pingInterval) { + clearInterval(pingInterval); + pingInterval = null; + } + }; + if (cacheConfig.REDIS_PING_INTERVAL > 0) { - pingInterval = setInterval( - () => keyvRedisClient.ping(), - cacheConfig.REDIS_PING_INTERVAL * 1000, - ); - keyvRedisClient.on('disconnect', () => clearInterval(pingInterval)); - keyvRedisClient.on('end', () => clearInterval(pingInterval)); + pingInterval = setInterval(() => { + if (keyvRedisClient && keyvRedisClient.isReady) { + keyvRedisClient.ping(); + } + }, cacheConfig.REDIS_PING_INTERVAL * 1000); + keyvRedisClient.on('disconnect', clearPingInterval); + keyvRedisClient.on('end', clearPingInterval); } }