import { Injectable, OnModuleDestroy, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import Redis from 'ioredis'; @Injectable() export class RedisService implements OnModuleDestroy { private readonly logger = new Logger(RedisService.name); private readonly client: Redis; constructor(private readonly configService: ConfigService) { const host = this.configService.get('REDIS_HOST') || 'localhost'; const port = this.configService.get('REDIS_PORT') || 6379; const password = this.configService.get('REDIS_PASSWORD'); const db = this.configService.get('REDIS_DB') || 1; this.client = new Redis({ host, port, password: password || undefined, db, }); this.client.on('connect', () => { this.logger.log(`Connected to Redis at ${host}:${port}, DB: ${db}`); }); this.client.on('error', (err) => { this.logger.error('Redis connection error:', err); }); } async onModuleDestroy() { await this.client.quit(); this.logger.log('Redis connection closed'); } getClient(): Redis { return this.client; } async get(key: string): Promise { return this.client.get(key); } async set(key: string, value: string, ttlSeconds?: number): Promise { if (ttlSeconds) { await this.client.setex(key, ttlSeconds, value); } else { await this.client.set(key, value); } } async del(key: string): Promise { await this.client.del(key); } async delByPattern(pattern: string): Promise { const keys = await this.client.keys(pattern); if (keys.length === 0) { return 0; } return this.client.del(...keys); } async exists(key: string): Promise { const result = await this.client.exists(key); return result === 1; } async setJson(key: string, value: T, ttlSeconds?: number): Promise { await this.set(key, JSON.stringify(value), ttlSeconds); } async getJson(key: string): Promise { const value = await this.get(key); if (!value) { return null; } try { return JSON.parse(value) as T; } catch { this.logger.warn(`Failed to parse JSON for key: ${key}`); return null; } } async ttl(key: string): Promise { return this.client.ttl(key); } }