170 lines
3.8 KiB
JavaScript
170 lines
3.8 KiB
JavaScript
const Redis = require('ioredis');
|
|
const config = require('./config.json');
|
|
|
|
/**
|
|
* Redis Connection - Direct connection to master
|
|
* For Sentinel HA from external clients, we connect directly to the master port
|
|
* and rely on manual failover by trying both ports
|
|
*/
|
|
const redisConfig = config.redis;
|
|
|
|
// Direct connection to master (port 11010)
|
|
const redisClient = new Redis({
|
|
host: redisConfig.cluster[0].host,
|
|
port: redisConfig.cluster[0].port,
|
|
password: redisConfig.password,
|
|
db: redisConfig.db,
|
|
keyPrefix: redisConfig.keyPrefix,
|
|
connectTimeout: 10000,
|
|
|
|
retryStrategy: (times) => {
|
|
if (times > 10) {
|
|
console.log(`⚠️ Redis retry exhausted after ${times} attempts`);
|
|
return null;
|
|
}
|
|
const delay = Math.min(times * 100, 3000);
|
|
console.log(`🔄 Redis retry attempt ${times}, delay ${delay}ms`);
|
|
return delay;
|
|
},
|
|
|
|
// Reconnect on READONLY error (slave promoted)
|
|
reconnectOnError: (err) => {
|
|
if (err.message.includes('READONLY')) {
|
|
console.log('⚠️ READONLY error detected - slave may have been promoted');
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
enableOfflineQueue: true,
|
|
maxRetriesPerRequest: null,
|
|
enableReadyCheck: true,
|
|
});
|
|
|
|
/**
|
|
* Redis Event Handlers
|
|
*/
|
|
redisClient.on('connect', () => {
|
|
console.log('✅ Redis client connected');
|
|
});
|
|
|
|
redisClient.on('ready', () => {
|
|
console.log('✅ Redis client ready');
|
|
});
|
|
|
|
redisClient.on('error', (err) => {
|
|
console.error('❌ Redis error:', err.message);
|
|
});
|
|
|
|
redisClient.on('close', () => {
|
|
console.log('⚠️ Redis client closed');
|
|
});
|
|
|
|
redisClient.on('reconnecting', () => {
|
|
console.log('🔄 Redis client reconnecting...');
|
|
});
|
|
|
|
/**
|
|
* Cache utility functions
|
|
*/
|
|
const cacheUtils = {
|
|
/**
|
|
* Get value from cache
|
|
*/
|
|
get: async (key) => {
|
|
try {
|
|
const value = await redisClient.get(key);
|
|
return value ? JSON.parse(value) : null;
|
|
} catch (error) {
|
|
console.error(`Error getting cache for key ${key}:`, error.message);
|
|
return null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Set value to cache with TTL
|
|
*/
|
|
set: async (key, value, ttl = 3600) => {
|
|
try {
|
|
const serialized = JSON.stringify(value);
|
|
await redisClient.setex(key, ttl, serialized);
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Error setting cache for key ${key}:`, error.message);
|
|
return false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Delete cache by key
|
|
*/
|
|
delete: async (key) => {
|
|
try {
|
|
await redisClient.del(key);
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Error deleting cache for key ${key}:`, error.message);
|
|
return false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Delete cache by pattern
|
|
*/
|
|
deletePattern: async (pattern) => {
|
|
try {
|
|
const keys = await redisClient.keys(pattern);
|
|
if (keys.length > 0) {
|
|
await redisClient.del(...keys);
|
|
}
|
|
return keys.length;
|
|
} catch (error) {
|
|
console.error(`Error deleting cache pattern ${pattern}:`, error.message);
|
|
return 0;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Check if key exists
|
|
*/
|
|
exists: async (key) => {
|
|
try {
|
|
const result = await redisClient.exists(key);
|
|
return result === 1;
|
|
} catch (error) {
|
|
console.error(`Error checking cache existence for key ${key}:`, error.message);
|
|
return false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Get TTL for key
|
|
*/
|
|
ttl: async (key) => {
|
|
try {
|
|
return await redisClient.ttl(key);
|
|
} catch (error) {
|
|
console.error(`Error getting TTL for key ${key}:`, error.message);
|
|
return -1;
|
|
}
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Close Redis connection
|
|
*/
|
|
const closeRedisConnection = async () => {
|
|
try {
|
|
await redisClient.quit();
|
|
console.log('✅ Redis connection closed gracefully');
|
|
} catch (error) {
|
|
console.error('❌ Error closing Redis connection:', error.message);
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
redisClient,
|
|
cacheUtils,
|
|
closeRedisConnection,
|
|
};
|