redis.util.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { createClient, RedisClientType } from 'redis';
  2. class RedisUtil {
  3. private client: RedisClientType | null = null;
  4. private static instance: RedisUtil;
  5. private constructor() {}
  6. public static getInstance(): RedisUtil {
  7. if (!RedisUtil.instance) {
  8. RedisUtil.instance = new RedisUtil();
  9. }
  10. return RedisUtil.instance;
  11. }
  12. async connect(): Promise<RedisClientType> {
  13. if (!this.client) {
  14. this.client = createClient({
  15. url: process.env.REDIS_URL || 'redis://127.0.0.1:6379'
  16. });
  17. this.client.on('error', (err) => {
  18. console.error('Redis Client Error:', err);
  19. });
  20. await this.client.connect();
  21. }
  22. return this.client;
  23. }
  24. async disconnect(): Promise<void> {
  25. if (this.client) {
  26. await this.client.disconnect();
  27. this.client = null;
  28. }
  29. }
  30. async setSessionKey(userId: number, sessionKey: string, ttlSeconds: number = 7200): Promise<void> {
  31. const client = await this.connect();
  32. const key = `session_key:${userId}`;
  33. await client.set(key, sessionKey, {
  34. EX: ttlSeconds // 默认2小时过期,与微信session_key有效期一致
  35. });
  36. }
  37. async getSessionKey(userId: number): Promise<string | null> {
  38. const client = await this.connect();
  39. const key = `session_key:${userId}`;
  40. return await client.get(key);
  41. }
  42. async deleteSessionKey(userId: number): Promise<void> {
  43. const client = await this.connect();
  44. const key = `session_key:${userId}`;
  45. await client.del(key);
  46. }
  47. async isSessionKeyValid(userId: number): Promise<boolean> {
  48. const sessionKey = await this.getSessionKey(userId);
  49. return !!sessionKey;
  50. }
  51. /**
  52. * 设置系统配置缓存
  53. */
  54. async setSystemConfig(tenantId: number, configKey: string, configValue: string, ttlSeconds: number = 3600): Promise<void> {
  55. const client = await this.connect();
  56. const key = `system_config:${tenantId}:${configKey}`;
  57. await client.set(key, configValue, {
  58. EX: ttlSeconds // 默认1小时过期
  59. });
  60. }
  61. /**
  62. * 获取系统配置缓存
  63. */
  64. async getSystemConfig(tenantId: number, configKey: string): Promise<string | null> {
  65. const client = await this.connect();
  66. const key = `system_config:${tenantId}:${configKey}`;
  67. return await client.get(key);
  68. }
  69. /**
  70. * 删除系统配置缓存
  71. */
  72. async deleteSystemConfig(tenantId: number, configKey: string): Promise<void> {
  73. const client = await this.connect();
  74. const key = `system_config:${tenantId}:${configKey}`;
  75. await client.del(key);
  76. }
  77. /**
  78. * 批量获取系统配置缓存
  79. */
  80. async getSystemConfigs(tenantId: number, configKeys: string[]): Promise<Record<string, string | null>> {
  81. const client = await this.connect();
  82. const keys = configKeys.map(key => `system_config:${tenantId}:${key}`);
  83. const values = await client.mGet(keys);
  84. const result: Record<string, string | null> = {};
  85. configKeys.forEach((key, index) => {
  86. result[key] = values[index];
  87. });
  88. return result;
  89. }
  90. /**
  91. * 设置空值缓存(防止缓存穿透)
  92. */
  93. async setNullSystemConfig(tenantId: number, configKey: string, ttlSeconds: number = 300): Promise<void> {
  94. const client = await this.connect();
  95. const key = `system_config:${tenantId}:${configKey}`;
  96. await client.set(key, '__NULL__', {
  97. EX: ttlSeconds // 默认5分钟过期
  98. });
  99. }
  100. /**
  101. * 检查是否为空值缓存
  102. */
  103. isNullValue(value: string | null): boolean {
  104. return value === '__NULL__';
  105. }
  106. /**
  107. * 清除租户的所有系统配置缓存
  108. */
  109. async clearTenantSystemConfigs(tenantId: number): Promise<void> {
  110. const client = await this.connect();
  111. const pattern = `system_config:${tenantId}:*`;
  112. // 使用SCAN命令遍历匹配的键并删除
  113. let cursor = 0;
  114. do {
  115. const result = await client.scan(cursor, {
  116. MATCH: pattern,
  117. COUNT: 100
  118. });
  119. cursor = result.cursor;
  120. const keys = result.keys;
  121. if (keys.length > 0) {
  122. await client.del(keys);
  123. }
  124. } while (cursor !== 0);
  125. }
  126. /**
  127. * 格式化系统配置缓存键
  128. */
  129. formatSystemConfigKey(tenantId: number, configKey: string): string {
  130. return `system_config:${tenantId}:${configKey}`;
  131. }
  132. }
  133. export const redisUtil = RedisUtil.getInstance();