Redis Is now optional

This commit is contained in:
NekoMonci12
2025-04-04 15:07:37 +07:00
parent c51a4a709c
commit 1ba3af244a

View File

@@ -6,68 +6,141 @@ class CacheManagerRedis {
* Example: { url: 'redis://localhost:6379' } * Example: { url: 'redis://localhost:6379' }
*/ */
constructor(options) { constructor(options) {
this.client = createClient(options); this.options = options;
this.client.on('error', (err) => console.error('Redis Client Error', err)); this.client = createClient(this.options);
this.client.connect(); 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) { normalize(input) {
return input.trim().toLowerCase(); return input.trim().toLowerCase();
} }
// Compute the Levenshtein distance between two strings
levenshtein(a, b) { levenshtein(a, b) {
const matrix = []; const matrix = [];
for (let i = 0; i <= b.length; i++) { for (let i = 0; i <= b.length; i++) matrix[i] = [i];
matrix[i] = [i]; for (let j = 0; j <= a.length; j++) matrix[0][j] = j;
}
for (let j = 0; j <= a.length; j++) {
matrix[0][j] = j;
}
for (let i = 1; i <= b.length; i++) { for (let i = 1; i <= b.length; i++) {
for (let j = 1; j <= a.length; j++) { for (let j = 1; j <= a.length; j++) {
if (b.charAt(i - 1) === a.charAt(j - 1)) { matrix[i][j] = b.charAt(i - 1) === a.charAt(j - 1)
matrix[i][j] = matrix[i - 1][j - 1]; ? matrix[i - 1][j - 1]
} else { : Math.min(
matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1,
matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1,
matrix[i][j - 1] + 1, matrix[i - 1][j] + 1
matrix[i - 1][j] + 1 );
);
}
} }
} }
return matrix[b.length][a.length]; return matrix[b.length][a.length];
} }
// Calculate similarity between two strings (1 means identical, 0 means completely different)
similarity(a, b) { similarity(a, b) {
const distance = this.levenshtein(a, b); const distance = this.levenshtein(a, b);
const maxLen = Math.max(a.length, b.length); const maxLen = Math.max(a.length, b.length);
if (maxLen === 0) return 1; return maxLen === 0 ? 1 : 1 - distance / maxLen;
return 1 - distance / maxLen;
} }
// Check the cache for a result that is at least 80% similar to the new input.
async getCachedResult(input) { async getCachedResult(input) {
const normalizedInput = this.normalize(input); await this._reconnectIfNeeded();
const keys = await this.client.keys('cache:*'); if (!this.connected) return null;
for (const key of keys) {
const storedNormalizedInput = key.slice(6); // remove "cache:" prefix try {
const sim = this.similarity(normalizedInput, storedNormalizedInput); const normalizedInput = this.normalize(input);
if (sim >= 0.8) { const keys = await this.client.keys('cache:*');
const cachedOutput = await this.client.get(key);
return cachedOutput; 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; return null;
} }
// Store the result in cache with key as normalized input
async setCache(input, output) { async setCache(input, output) {
const normalizedInput = this.normalize(input); await this._reconnectIfNeeded();
await this.client.set(`cache:${normalizedInput}`, output, { EX: 3600 }); 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;
}
} }
} }