diff --git a/cacheManagerRedis.js b/cacheManagerRedis.js index 702864a..c55e80b 100644 --- a/cacheManagerRedis.js +++ b/cacheManagerRedis.js @@ -6,68 +6,141 @@ class CacheManagerRedis { * Example: { url: 'redis://localhost:6379' } */ constructor(options) { - this.client = createClient(options); - this.client.on('error', (err) => console.error('Redis Client Error', err)); - this.client.connect(); + this.options = options; + this.client = createClient(this.options); + this.connected = false; + this.connecting = false; + + this.redisErrorCount = 0; + this.redisErrorLimit = 3; + + this.client.on('error', (err) => { + this.connected = false; + + if (this.redisErrorCount < this.redisErrorLimit) { + console.error('[RedisCache] Redis Client Error:', err.message); + this.redisErrorCount++; + + if (this.redisErrorCount === this.redisErrorLimit) { + console.warn('[RedisCache] Reached max Redis error log limit. Further errors will be silenced.'); + } + } + }); + + this._initialConnect(); + } + + async _initialConnect() { + try { + this.connecting = true; + await this.client.connect(); + this.connected = true; + this.redisErrorCount = 0; + console.log('[RedisCache] Connected to Redis.'); + } catch (err) { + console.error('[RedisCache] Initial Redis connection failed:', err.message); + this.connected = false; + } finally { + this.connecting = false; + } + } + + async _reconnectIfNeeded() { + if (!this.connected && !this.connecting) { + console.warn('[RedisCache] Attempting to reconnect to Redis...'); + try { + this.connecting = true; + this.client = createClient(this.options); + + // Reset listener and error limiter + this.redisErrorCount = 0; + this.client.on('error', (err) => { + this.connected = false; + + if (this.redisErrorCount < this.redisErrorLimit) { + console.error('[RedisCache] Redis Client Error:', err.message); + this.redisErrorCount++; + + if (this.redisErrorCount === this.redisErrorLimit) { + console.warn('[RedisCache] Reached max Redis error log limit. Further errors will be silenced.'); + } + } + }); + + await this.client.connect(); + this.connected = true; + console.log('[RedisCache] Reconnected to Redis.'); + } catch (err) { + console.error('[RedisCache] Reconnection failed:', err.message); + } finally { + this.connecting = false; + } + } } - // Normalize input for consistent comparison normalize(input) { return input.trim().toLowerCase(); } - // Compute the Levenshtein distance between two strings levenshtein(a, b) { const matrix = []; - for (let i = 0; i <= b.length; i++) { - matrix[i] = [i]; - } - for (let j = 0; j <= a.length; j++) { - matrix[0][j] = j; - } + for (let i = 0; i <= b.length; i++) matrix[i] = [i]; + for (let j = 0; j <= a.length; j++) matrix[0][j] = j; + for (let i = 1; i <= b.length; i++) { for (let j = 1; j <= a.length; j++) { - if (b.charAt(i - 1) === a.charAt(j - 1)) { - matrix[i][j] = matrix[i - 1][j - 1]; - } else { - matrix[i][j] = Math.min( - matrix[i - 1][j - 1] + 1, - matrix[i][j - 1] + 1, - matrix[i - 1][j] + 1 - ); - } + matrix[i][j] = b.charAt(i - 1) === a.charAt(j - 1) + ? matrix[i - 1][j - 1] + : Math.min( + matrix[i - 1][j - 1] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j] + 1 + ); } } return matrix[b.length][a.length]; } - // Calculate similarity between two strings (1 means identical, 0 means completely different) similarity(a, b) { const distance = this.levenshtein(a, b); const maxLen = Math.max(a.length, b.length); - if (maxLen === 0) return 1; - return 1 - distance / maxLen; + return maxLen === 0 ? 1 : 1 - distance / maxLen; } - // Check the cache for a result that is at least 80% similar to the new input. async getCachedResult(input) { - const normalizedInput = this.normalize(input); - const keys = await this.client.keys('cache:*'); - for (const key of keys) { - const storedNormalizedInput = key.slice(6); // remove "cache:" prefix - const sim = this.similarity(normalizedInput, storedNormalizedInput); - if (sim >= 0.8) { - const cachedOutput = await this.client.get(key); - return cachedOutput; + await this._reconnectIfNeeded(); + if (!this.connected) return null; + + try { + const normalizedInput = this.normalize(input); + const keys = await this.client.keys('cache:*'); + + for (const key of keys) { + const storedNormalizedInput = key.slice(6); + const sim = this.similarity(normalizedInput, storedNormalizedInput); + if (sim >= 0.8) { + return await this.client.get(key); + } } + } catch (err) { + console.error('[RedisCache] Error in getCachedResult:', err.message); + this.connected = false; } + return null; } - // Store the result in cache with key as normalized input async setCache(input, output) { - const normalizedInput = this.normalize(input); - await this.client.set(`cache:${normalizedInput}`, output, { EX: 3600 }); + await this._reconnectIfNeeded(); + if (!this.connected) return; + + try { + const normalizedInput = this.normalize(input); + await this.client.set(`cache:${normalizedInput}`, output, { EX: 3600 }); + } catch (err) { + console.error('[RedisCache] Error in setCache:', err.message); + this.connected = false; + } } }