/** * @file Redis服务类 * @author hotok * @date 2025-06-29 * @lastEditor hotok * @lastEditTime 2025-06-29 * @description 精简的Redis连接服务类,支持连接管理、状态跟踪和健康检查 */ import { createClient } from 'redis'; import { redisConfig, getRedisUrl } from '@/config/redis.config'; import { Logger } from '@/plugins/logger/logger.service'; import type { RedisConnectionStatus, RedisConnectionInfo, RedisHealthCheckResult } from '@/type/redis.type'; /** * Redis服务类 * 使用单例模式管理Redis连接 */ export class RedisService { /** 单例实例 */ private static instance: RedisService | null = null; /** Redis客户端实例 */ private _client: any = null; /** 连接状态信息 */ private _connectionInfo: RedisConnectionInfo; /** 初始化标志 */ private _isInitialized = false; /** * 私有构造函数,防止外部实例化 */ private constructor() { this._connectionInfo = { status: 'disconnected', host: redisConfig.host, port: redisConfig.port, database: redisConfig.database, connectName: redisConfig.connectName, isConnected: false, }; } /** * 获取单例实例 */ public static getInstance(): RedisService { if (!RedisService.instance) { RedisService.instance = new RedisService(); } return RedisService.instance; } /** * 获取Redis客户端实例 */ public get client(): any { if (!this._client) { throw new Error('Redis未初始化,请先调用 initialize() 方法'); } return this._client; } /** * 获取连接状态信息 */ public get connectionInfo(): RedisConnectionInfo { return { ...this._connectionInfo }; } /** * 检查是否已初始化 */ public get isInitialized(): boolean { return this._isInitialized; } /** * 验证Redis配置 */ private validateConfig(): void { if (!redisConfig.host || !redisConfig.port) { throw new Error('Redis配置无效:缺少host或port'); } if (redisConfig.port < 1 || redisConfig.port > 65535) { throw new Error(`Redis端口号无效: ${redisConfig.port}`); } } /** * 更新连接状态 */ private updateConnectionStatus(status: RedisConnectionStatus, error?: string): void { this._connectionInfo.status = status; this._connectionInfo.error = error; this._connectionInfo.isConnected = status === 'connected'; if (status === 'connected') { this._connectionInfo.connectedAt = new Date(); this._connectionInfo.error = undefined; } } /** * 初始化Redis连接 */ public async initialize(): Promise { // 防止重复初始化 if (this._isInitialized && this._client) { Logger.info('Redis 已初始化,返回现有实例'); return this._client; } try { this.validateConfig(); this.updateConnectionStatus('connecting'); // 创建Redis客户端 this._client = createClient({ name: redisConfig.connectName, username: redisConfig.username, password: redisConfig.password, database: redisConfig.database, url: getRedisUrl(), }); // 连接Redis await this._client.connect(); // 测试连接 await this._client.ping(); this._isInitialized = true; this.updateConnectionStatus('connected'); Logger.info({ message: 'Redis 初始化成功', host: redisConfig.host, port: redisConfig.port, database: redisConfig.database, connectName: redisConfig.connectName, }); return this._client; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.updateConnectionStatus('error', errorMessage); Logger.error(new Error(`Redis 初始化失败: ${errorMessage}`)); throw new Error(`Redis 初始化失败: ${errorMessage}`); } } /** * 检查连接状态 */ public async checkConnection(): Promise { try { if (!this._client || !this._connectionInfo.isConnected) { return false; } await this._client.ping(); return true; } catch (error) { Logger.error(error instanceof Error ? error : new Error('Redis连接检查失败')); return false; } } /** * 执行健康检查 */ public async healthCheck(): Promise { const startTime = Date.now(); try { if (!this._client) { return { status: 'unhealthy', responseTime: 0, connectionInfo: this.connectionInfo, error: 'Redis客户端未初始化', }; } // 执行ping测试 await this._client.ping(); const responseTime = Date.now() - startTime; return { status: 'healthy', responseTime, connectionInfo: this.connectionInfo, }; } catch (error) { const responseTime = Date.now() - startTime; const errorMessage = error instanceof Error ? error.message : String(error); return { status: 'unhealthy', responseTime, connectionInfo: this.connectionInfo, error: errorMessage, }; } } /** * 优雅关闭连接 */ public async close(): Promise { try { if (this._client && this._connectionInfo.isConnected) { await this._client.quit(); this._client = null; this.updateConnectionStatus('disconnected'); this._isInitialized = false; Logger.info('Redis连接已关闭'); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); Logger.error(new Error(`关闭Redis连接时出错: ${errorMessage}`)); throw new Error(`关闭Redis连接失败: ${errorMessage}`); } } /** * 重新连接 */ public async reconnect(): Promise { Logger.info('正在重新连接Redis...'); // 先关闭现有连接 await this.close(); // 重新初始化连接 return await this.initialize(); } } /** * ============================================== * 主要导出 - 推荐使用的API * ============================================== */ /** * Redis服务单例实例 * * @description 获取RedisService的单例实例,推荐的使用方式 * @example * ```typescript * import { redisService } from '@/plugins/redis/redis.service'; * * // 初始化Redis * await redisService.initialize(); * * // 获取客户端实例 * const client = redisService.client; * * // 检查连接状态 * const isConnected = await redisService.checkConnection(); * ``` */ export const redisService = RedisService.getInstance(); /** * ============================================== * 向后兼容导出 - 保持原有函数式API * ============================================== */ /** * 创建并初始化Redis连接 * * @description 向后兼容的初始化方法,内部调用redisService.initialize() * @returns {Promise} 返回初始化后的Redis客户端实例 * * @example * ```typescript * import { createRedisClient } from '@/plugins/redis/redis.service'; * * const client = await createRedisClient(); * ``` * * @deprecated 推荐使用 redisService.initialize() 替代 */ export const createRedisClient = () => redisService.initialize(); /** * 获取Redis连接状态信息 * * @description 向后兼容的状态获取方法,内部调用redisService.connectionInfo * @returns {RedisConnectionInfo} 返回Redis连接状态信息 * * @example * ```typescript * import { getRedisConnectionInfo } from '@/plugins/redis/redis.service'; * * const info = getRedisConnectionInfo(); * console.log(`Redis状态: ${info.status}`); * ``` * * @deprecated 推荐使用 redisService.connectionInfo 替代 */ export const getRedisConnectionInfo = () => redisService.connectionInfo; /** * 检查Redis连接状态 * * @description 向后兼容的连接检查方法,内部调用redisService.checkConnection() * @returns {Promise} 返回连接是否正常 * * @example * ```typescript * import { checkRedisConnection } from '@/plugins/redis/redis.service'; * * const isConnected = await checkRedisConnection(); * if (!isConnected) { * console.log('Redis连接异常'); * } * ``` * * @deprecated 推荐使用 redisService.checkConnection() 替代 */ export const checkRedisConnection = () => redisService.checkConnection(); /** * 优雅关闭Redis连接 * * @description 向后兼容的连接关闭方法,内部调用redisService.close() * @returns {Promise} 返回关闭操作的Promise * * @example * ```typescript * import { closeRedisConnection } from '@/plugins/redis/redis.service'; * * // 应用关闭时清理资源 * process.on('SIGTERM', async () => { * await closeRedisConnection(); * process.exit(0); * }); * ``` * * @deprecated 推荐使用 redisService.close() 替代 */ export const closeRedisConnection = () => redisService.close(); /** * 重新连接Redis * * @description 向后兼容的重连方法,内部调用redisService.reconnect() * @returns {Promise} 返回重新连接后的客户端实例 * * @example * ```typescript * import { reconnectRedis } from '@/plugins/redis/redis.service'; * * try { * const client = await reconnectRedis(); * console.log('Redis重连成功'); * } catch (error) { * console.error('Redis重连失败:', error); * } * ``` * * @deprecated 推荐使用 redisService.reconnect() 替代 */ export const reconnectRedis = () => redisService.reconnect(); /** * 获取Redis客户端实例 * * @description 向后兼容的客户端获取方法,内部调用redisService.client * @returns {any} 返回Redis客户端实例 * @throws {Error} 如果Redis未初始化则抛出错误 * * @example * ```typescript * import { redis } from '@/plugins/redis/redis.service'; * * // 确保先初始化 * await createRedisClient(); * * // 获取客户端实例 * const client = redis(); * const result = await client.get('key'); * ``` * * @deprecated 推荐使用 redisService.client 替代 */ export const redis = () => redisService.client;