修改管理后台
This commit is contained in:
743
backend/services/cacheService.js
Normal file
743
backend/services/cacheService.js
Normal file
@@ -0,0 +1,743 @@
|
||||
/**
|
||||
* Redis缓存服务
|
||||
* @file cacheService.js
|
||||
* @description 提供高性能Redis缓存功能,优化数据访问速度
|
||||
*/
|
||||
const redis = require('redis');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
/**
|
||||
* 缓存配置
|
||||
*/
|
||||
const CACHE_CONFIG = {
|
||||
host: process.env.REDIS_HOST || 'localhost',
|
||||
port: process.env.REDIS_PORT || 6379,
|
||||
password: process.env.REDIS_PASSWORD || '',
|
||||
db: process.env.REDIS_DB || 0,
|
||||
|
||||
// 默认TTL配置(秒)
|
||||
ttl: {
|
||||
short: 5 * 60, // 5分钟
|
||||
medium: 30 * 60, // 30分钟
|
||||
long: 2 * 60 * 60, // 2小时
|
||||
daily: 24 * 60 * 60 // 24小时
|
||||
},
|
||||
|
||||
// 键名前缀
|
||||
prefix: 'nxxm:',
|
||||
|
||||
// 连接配置
|
||||
connect_timeout: 10000,
|
||||
command_timeout: 5000,
|
||||
retry_unfulfilled_commands: true,
|
||||
retry_delay_on_failure: 100,
|
||||
max_retry_delay: 3000
|
||||
};
|
||||
|
||||
/**
|
||||
* Redis缓存服务类
|
||||
*/
|
||||
class CacheService {
|
||||
constructor() {
|
||||
this.client = null;
|
||||
this.isConnected = false;
|
||||
this.stats = {
|
||||
hits: 0,
|
||||
misses: 0,
|
||||
errors: 0,
|
||||
totalOperations: 0
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Redis连接
|
||||
*/
|
||||
async init() {
|
||||
try {
|
||||
this.client = redis.createClient({
|
||||
url: `redis://${CACHE_CONFIG.host}:${CACHE_CONFIG.port}`,
|
||||
password: CACHE_CONFIG.password || undefined,
|
||||
database: CACHE_CONFIG.db,
|
||||
socket: {
|
||||
connectTimeout: CACHE_CONFIG.connect_timeout,
|
||||
commandTimeout: CACHE_CONFIG.command_timeout,
|
||||
reconnectStrategy: (retries) => {
|
||||
if (retries > 10) {
|
||||
logger.error('Redis重连次数超过限制,停止重连');
|
||||
return false;
|
||||
}
|
||||
return Math.min(retries * 100, 3000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 事件监听
|
||||
this.client.on('connect', () => {
|
||||
logger.info('Redis连接已建立');
|
||||
this.isConnected = true;
|
||||
});
|
||||
|
||||
this.client.on('ready', () => {
|
||||
logger.info('Redis客户端已就绪');
|
||||
});
|
||||
|
||||
this.client.on('error', (error) => {
|
||||
logger.error('Redis连接错误:', error);
|
||||
this.isConnected = false;
|
||||
this.stats.errors++;
|
||||
});
|
||||
|
||||
this.client.on('end', () => {
|
||||
logger.warn('Redis连接已断开');
|
||||
this.isConnected = false;
|
||||
});
|
||||
|
||||
this.client.on('reconnecting', () => {
|
||||
logger.info('正在重新连接Redis...');
|
||||
});
|
||||
|
||||
// 连接到Redis
|
||||
await this.client.connect();
|
||||
|
||||
logger.info('Redis缓存服务初始化成功');
|
||||
} catch (error) {
|
||||
logger.error('Redis缓存服务初始化失败:', error);
|
||||
this.isConnected = false;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缓存键名
|
||||
* @param {string} key 键名
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {string} 完整键名
|
||||
*/
|
||||
generateKey(key, namespace = 'default') {
|
||||
return `${CACHE_CONFIG.prefix}${namespace}:${key}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
* @param {string} key 键名
|
||||
* @param {*} value 值
|
||||
* @param {number} ttl 过期时间(秒)
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {boolean} 设置结果
|
||||
*/
|
||||
async set(key, value, ttl = CACHE_CONFIG.ttl.medium, namespace = 'default') {
|
||||
if (!this.isConnected) {
|
||||
logger.warn('Redis未连接,缓存设置跳过');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const fullKey = this.generateKey(key, namespace);
|
||||
const serializedValue = JSON.stringify(value);
|
||||
|
||||
await this.client.setEx(fullKey, ttl, serializedValue);
|
||||
|
||||
this.stats.totalOperations++;
|
||||
logger.debug(`缓存设置成功: ${fullKey}, TTL: ${ttl}s`);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error(`缓存设置失败 ${key}:`, error);
|
||||
this.stats.errors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存
|
||||
* @param {string} key 键名
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {*} 缓存值或null
|
||||
*/
|
||||
async get(key, namespace = 'default') {
|
||||
if (!this.isConnected) {
|
||||
logger.warn('Redis未连接,缓存获取跳过');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const fullKey = this.generateKey(key, namespace);
|
||||
const value = await this.client.get(fullKey);
|
||||
|
||||
this.stats.totalOperations++;
|
||||
|
||||
if (value === null) {
|
||||
this.stats.misses++;
|
||||
logger.debug(`缓存未命中: ${fullKey}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
this.stats.hits++;
|
||||
logger.debug(`缓存命中: ${fullKey}`);
|
||||
|
||||
return JSON.parse(value);
|
||||
} catch (error) {
|
||||
logger.error(`缓存获取失败 ${key}:`, error);
|
||||
this.stats.errors++;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @param {string} key 键名
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {boolean} 删除结果
|
||||
*/
|
||||
async del(key, namespace = 'default') {
|
||||
if (!this.isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const fullKey = this.generateKey(key, namespace);
|
||||
const result = await this.client.del(fullKey);
|
||||
|
||||
this.stats.totalOperations++;
|
||||
logger.debug(`缓存删除: ${fullKey}, 结果: ${result}`);
|
||||
|
||||
return result > 0;
|
||||
} catch (error) {
|
||||
logger.error(`缓存删除失败 ${key}:`, error);
|
||||
this.stats.errors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查缓存是否存在
|
||||
* @param {string} key 键名
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {boolean} 是否存在
|
||||
*/
|
||||
async exists(key, namespace = 'default') {
|
||||
if (!this.isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const fullKey = this.generateKey(key, namespace);
|
||||
const result = await this.client.exists(fullKey);
|
||||
|
||||
this.stats.totalOperations++;
|
||||
return result === 1;
|
||||
} catch (error) {
|
||||
logger.error(`缓存存在检查失败 ${key}:`, error);
|
||||
this.stats.errors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置过期时间
|
||||
* @param {string} key 键名
|
||||
* @param {number} ttl 过期时间(秒)
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {boolean} 设置结果
|
||||
*/
|
||||
async expire(key, ttl, namespace = 'default') {
|
||||
if (!this.isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const fullKey = this.generateKey(key, namespace);
|
||||
const result = await this.client.expire(fullKey, ttl);
|
||||
|
||||
this.stats.totalOperations++;
|
||||
return result === 1;
|
||||
} catch (error) {
|
||||
logger.error(`设置过期时间失败 ${key}:`, error);
|
||||
this.stats.errors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取剩余过期时间
|
||||
* @param {string} key 键名
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {number} 剩余秒数,-1表示永不过期,-2表示键不存在
|
||||
*/
|
||||
async ttl(key, namespace = 'default') {
|
||||
if (!this.isConnected) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
try {
|
||||
const fullKey = this.generateKey(key, namespace);
|
||||
const result = await this.client.ttl(fullKey);
|
||||
|
||||
this.stats.totalOperations++;
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error(`获取过期时间失败 ${key}:`, error);
|
||||
this.stats.errors++;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空指定命名空间的所有缓存
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {number} 删除的键数量
|
||||
*/
|
||||
async clearNamespace(namespace) {
|
||||
if (!this.isConnected) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
const pattern = `${CACHE_CONFIG.prefix}${namespace}:*`;
|
||||
const keys = await this.client.keys(pattern);
|
||||
|
||||
if (keys.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const result = await this.client.del(keys);
|
||||
|
||||
this.stats.totalOperations++;
|
||||
logger.info(`清空命名空间 ${namespace}: 删除了 ${result} 个键`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error(`清空命名空间失败 ${namespace}:`, error);
|
||||
this.stats.errors++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置缓存
|
||||
* @param {Object} keyValuePairs 键值对
|
||||
* @param {number} ttl 过期时间
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {boolean} 设置结果
|
||||
*/
|
||||
async mSet(keyValuePairs, ttl = CACHE_CONFIG.ttl.medium, namespace = 'default') {
|
||||
if (!this.isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const pipeline = this.client.multi();
|
||||
|
||||
Object.entries(keyValuePairs).forEach(([key, value]) => {
|
||||
const fullKey = this.generateKey(key, namespace);
|
||||
const serializedValue = JSON.stringify(value);
|
||||
pipeline.setEx(fullKey, ttl, serializedValue);
|
||||
});
|
||||
|
||||
await pipeline.exec();
|
||||
|
||||
this.stats.totalOperations += Object.keys(keyValuePairs).length;
|
||||
logger.debug(`批量缓存设置成功: ${Object.keys(keyValuePairs).length} 个键`);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error('批量缓存设置失败:', error);
|
||||
this.stats.errors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取缓存
|
||||
* @param {Array} keys 键名数组
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {Object} 键值对结果
|
||||
*/
|
||||
async mGet(keys, namespace = 'default') {
|
||||
if (!this.isConnected) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
const fullKeys = keys.map(key => this.generateKey(key, namespace));
|
||||
const values = await this.client.mGet(fullKeys);
|
||||
|
||||
const result = {};
|
||||
keys.forEach((key, index) => {
|
||||
const value = values[index];
|
||||
if (value !== null) {
|
||||
try {
|
||||
result[key] = JSON.parse(value);
|
||||
this.stats.hits++;
|
||||
} catch (error) {
|
||||
logger.warn(`解析缓存值失败 ${key}:`, error);
|
||||
result[key] = null;
|
||||
}
|
||||
} else {
|
||||
result[key] = null;
|
||||
this.stats.misses++;
|
||||
}
|
||||
});
|
||||
|
||||
this.stats.totalOperations += keys.length;
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error('批量缓存获取失败:', error);
|
||||
this.stats.errors++;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存包装器 - 自动缓存函数结果
|
||||
* @param {string} key 缓存键
|
||||
* @param {Function} fn 异步函数
|
||||
* @param {number} ttl 过期时间
|
||||
* @param {string} namespace 命名空间
|
||||
* @returns {*} 函数结果
|
||||
*/
|
||||
async wrap(key, fn, ttl = CACHE_CONFIG.ttl.medium, namespace = 'default') {
|
||||
// 首先尝试从缓存获取
|
||||
const cached = await this.get(key, namespace);
|
||||
if (cached !== null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
try {
|
||||
// 缓存未命中,执行函数
|
||||
const result = await fn();
|
||||
|
||||
// 将结果存入缓存
|
||||
await this.set(key, result, ttl, namespace);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error(`缓存包装器执行失败 ${key}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存统计信息
|
||||
* @returns {Object} 统计信息
|
||||
*/
|
||||
getStats() {
|
||||
const hitRate = this.stats.totalOperations > 0
|
||||
? (this.stats.hits / (this.stats.hits + this.stats.misses)) * 100
|
||||
: 0;
|
||||
|
||||
return {
|
||||
...this.stats,
|
||||
hitRate: hitRate.toFixed(2) + '%',
|
||||
isConnected: this.isConnected,
|
||||
config: {
|
||||
host: CACHE_CONFIG.host,
|
||||
port: CACHE_CONFIG.port,
|
||||
db: CACHE_CONFIG.db
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Redis服务器信息
|
||||
* @returns {Object} 服务器信息
|
||||
*/
|
||||
async getServerInfo() {
|
||||
if (!this.isConnected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const info = await this.client.info();
|
||||
const memory = await this.client.info('memory');
|
||||
const stats = await this.client.info('stats');
|
||||
|
||||
return {
|
||||
version: this.extractInfoValue(info, 'redis_version'),
|
||||
uptime: this.extractInfoValue(info, 'uptime_in_seconds'),
|
||||
memory: {
|
||||
used: this.extractInfoValue(memory, 'used_memory_human'),
|
||||
peak: this.extractInfoValue(memory, 'used_memory_peak_human'),
|
||||
fragmentation: this.extractInfoValue(memory, 'mem_fragmentation_ratio')
|
||||
},
|
||||
stats: {
|
||||
connections: this.extractInfoValue(stats, 'total_connections_received'),
|
||||
commands: this.extractInfoValue(stats, 'total_commands_processed'),
|
||||
hits: this.extractInfoValue(stats, 'keyspace_hits'),
|
||||
misses: this.extractInfoValue(stats, 'keyspace_misses')
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error('获取Redis服务器信息失败:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从INFO字符串中提取值
|
||||
* @private
|
||||
*/
|
||||
extractInfoValue(infoString, key) {
|
||||
const regex = new RegExp(`${key}:(.+)`);
|
||||
const match = infoString.match(regex);
|
||||
return match ? match[1].trim() : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 健康检查
|
||||
* @returns {Object} 健康状态
|
||||
*/
|
||||
async healthCheck() {
|
||||
try {
|
||||
if (!this.isConnected) {
|
||||
return {
|
||||
status: 'unhealthy',
|
||||
message: 'Redis连接断开',
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
|
||||
// 执行简单的ping测试
|
||||
const pong = await this.client.ping();
|
||||
|
||||
if (pong === 'PONG') {
|
||||
return {
|
||||
status: 'healthy',
|
||||
message: 'Redis连接正常',
|
||||
stats: this.getStats(),
|
||||
timestamp: new Date()
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: 'unhealthy',
|
||||
message: 'Redis ping响应异常',
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Redis健康检查失败:', error);
|
||||
return {
|
||||
status: 'unhealthy',
|
||||
message: 'Redis健康检查失败',
|
||||
error: error.message,
|
||||
timestamp: new Date()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭连接
|
||||
*/
|
||||
async close() {
|
||||
try {
|
||||
if (this.client && this.isConnected) {
|
||||
await this.client.quit();
|
||||
logger.info('Redis连接已关闭');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('关闭Redis连接失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有缓存
|
||||
* @returns {boolean} 清空结果
|
||||
*/
|
||||
async flushAll() {
|
||||
if (!this.isConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.client.flushDb();
|
||||
logger.info('Redis缓存已清空');
|
||||
|
||||
// 重置统计
|
||||
this.stats = {
|
||||
hits: 0,
|
||||
misses: 0,
|
||||
errors: 0,
|
||||
totalOperations: 0
|
||||
};
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error('清空Redis缓存失败:', error);
|
||||
this.stats.errors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存键名常量
|
||||
*/
|
||||
const CACHE_KEYS = {
|
||||
// 用户相关
|
||||
USER_LIST: 'users:list',
|
||||
USER_PROFILE: (id) => `users:profile:${id}`,
|
||||
USER_PERMISSIONS: (id) => `users:permissions:${id}`,
|
||||
|
||||
// 农场相关
|
||||
FARM_LIST: 'farms:list',
|
||||
FARM_DETAIL: (id) => `farms:detail:${id}`,
|
||||
FARM_ANIMALS: (id) => `farms:animals:${id}`,
|
||||
FARM_DEVICES: (id) => `farms:devices:${id}`,
|
||||
|
||||
// 设备相关
|
||||
DEVICE_LIST: 'devices:list',
|
||||
DEVICE_STATUS: (id) => `devices:status:${id}`,
|
||||
DEVICE_METRICS: (id) => `devices:metrics:${id}`,
|
||||
|
||||
// 统计数据
|
||||
STATS_DASHBOARD: 'stats:dashboard',
|
||||
STATS_FARMS: 'stats:farms',
|
||||
STATS_DEVICES: 'stats:devices',
|
||||
STATS_ANIMALS: 'stats:animals',
|
||||
STATS_ALERTS: 'stats:alerts',
|
||||
|
||||
// 系统配置
|
||||
SYSTEM_CONFIG: 'system:config',
|
||||
MENU_PERMISSIONS: 'system:menus',
|
||||
|
||||
// 搜索结果
|
||||
SEARCH_RESULTS: (type, query) => `search:${type}:${Buffer.from(query).toString('base64')}`
|
||||
};
|
||||
|
||||
/**
|
||||
* 高级缓存功能
|
||||
*/
|
||||
class AdvancedCache extends CacheService {
|
||||
/**
|
||||
* 缓存列表数据(带分页)
|
||||
* @param {string} key 基础键名
|
||||
* @param {Array} data 数据数组
|
||||
* @param {Object} pagination 分页信息
|
||||
* @param {number} ttl 过期时间
|
||||
*/
|
||||
async setListData(key, data, pagination = {}, ttl = CACHE_CONFIG.ttl.medium) {
|
||||
const cacheData = {
|
||||
data,
|
||||
pagination,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
return await this.set(key, cacheData, ttl, 'lists');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取列表数据
|
||||
* @param {string} key 键名
|
||||
* @returns {Object} 列表数据和分页信息
|
||||
*/
|
||||
async getListData(key) {
|
||||
const cached = await this.get(key, 'lists');
|
||||
|
||||
if (cached && cached.data) {
|
||||
return {
|
||||
data: cached.data,
|
||||
pagination: cached.pagination || {},
|
||||
fromCache: true,
|
||||
cacheTimestamp: cached.timestamp
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能缓存失效
|
||||
* @param {string} entity 实体类型
|
||||
* @param {string} operation 操作类型
|
||||
* @param {number} entityId 实体ID
|
||||
*/
|
||||
async invalidateRelated(entity, operation, entityId = null) {
|
||||
const patterns = [];
|
||||
|
||||
switch (entity) {
|
||||
case 'farm':
|
||||
patterns.push('farms:*', 'stats:*');
|
||||
if (entityId) {
|
||||
patterns.push(`farms:detail:${entityId}`, `farms:animals:${entityId}`, `farms:devices:${entityId}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'device':
|
||||
patterns.push('devices:*', 'stats:*');
|
||||
if (entityId) {
|
||||
patterns.push(`devices:status:${entityId}`, `devices:metrics:${entityId}`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'animal':
|
||||
patterns.push('animals:*', 'stats:*');
|
||||
break;
|
||||
|
||||
case 'user':
|
||||
patterns.push('users:*');
|
||||
if (entityId) {
|
||||
patterns.push(`users:profile:${entityId}`, `users:permissions:${entityId}`);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
patterns.push('stats:*'); // 默认清理统计缓存
|
||||
}
|
||||
|
||||
let totalDeleted = 0;
|
||||
for (const pattern of patterns) {
|
||||
const deleted = await this.clearPattern(pattern);
|
||||
totalDeleted += deleted;
|
||||
}
|
||||
|
||||
logger.info(`智能缓存失效: ${entity}/${operation}, 清理了 ${totalDeleted} 个缓存键`);
|
||||
return totalDeleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按模式清理缓存
|
||||
* @private
|
||||
*/
|
||||
async clearPattern(pattern) {
|
||||
if (!this.isConnected) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
const fullPattern = `${CACHE_CONFIG.prefix}${pattern}`;
|
||||
const keys = await this.client.keys(fullPattern);
|
||||
|
||||
if (keys.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const result = await this.client.del(keys);
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error(`按模式清理缓存失败 ${pattern}:`, error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建缓存服务实例
|
||||
const cacheService = new AdvancedCache();
|
||||
|
||||
// 优雅关闭处理
|
||||
process.on('SIGINT', async () => {
|
||||
logger.info('收到SIGINT信号,正在关闭Redis连接...');
|
||||
await cacheService.close();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', async () => {
|
||||
logger.info('收到SIGTERM信号,正在关闭Redis连接...');
|
||||
await cacheService.close();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
cacheService,
|
||||
CACHE_KEYS,
|
||||
CACHE_CONFIG
|
||||
};
|
||||
Reference in New Issue
Block a user