import { createLoggerWithContext } from "@midday/logger"; import { getSharedRedisClient } from "./shared-redis"; const logger = createLoggerWithContext("redis-cache"); export class RedisCache { private prefix: string; private defaultTTL: number; constructor(prefix: string, defaultTTL: number = 30 * 60) { this.prefix = prefix; this.defaultTTL = defaultTTL; } // Get client lazily - allows picking up reconnected clients private get redis() { return getSharedRedisClient(); } private parseValue(value: string | null): T | undefined { if (!value) return undefined; try { return JSON.parse(value) as T; } catch { // If parsing fails, return the raw string (for backwards compatibility) return value as unknown as T; } } private stringifyValue(value: unknown): string { if (typeof value === "string") { return value; } return JSON.stringify(value); } private getKey(key: string): string { return `${this.prefix}:${key}`; } async get(key: string): Promise { try { const value = await this.redis.get(this.getKey(key)); return this.parseValue(value); } catch (error) { logger.error(`Get error for ${this.prefix} cache`, { key, error: error instanceof Error ? error.message : String(error), }); return undefined; } } async set(key: string, value: unknown, ttlSeconds?: number): Promise { try { const serializedValue = this.stringifyValue(value); const redisKey = this.getKey(key); const ttl = ttlSeconds ?? this.defaultTTL; if (ttl > 0) { await this.redis.send("SETEX", [ redisKey, ttl.toString(), serializedValue, ]); } else { await this.redis.set(redisKey, serializedValue); } } catch (error) { logger.error(`Set error for ${this.prefix} cache`, { key, error: error instanceof Error ? error.message : String(error), }); } } async delete(key: string): Promise { try { await this.redis.del(this.getKey(key)); } catch (error) { logger.error(`Delete error for ${this.prefix} cache`, { key, error: error instanceof Error ? error.message : String(error), }); } } async healthCheck(): Promise { try { await this.redis.send("PING", []); } catch (error) { throw new Error(`Redis health check failed: ${error}`); } } }