1import { Injectable, OnModuleDestroy, OnModuleInit } from "@nestjs/common";
2import Redis from "ioredis";
3import { loadEnv } from "../config/env.js";
4import { logger } from "./logger.js";
5
6
11@Injectable()
12export class RedisService implements OnModuleInit, OnModuleDestroy {
13 private readonly client: Redis;
14
15 constructor() {
16 this.client = new Redis(loadEnv().REDIS_URL, {
17 maxRetriesPerRequest: 2,
18 retryStrategy: (times: number) => Math.min(times * 500, 5000)
19 });
20 }
21
22 onModuleInit(): void {
23 this.client.on("error", (err: Error) => {
24 logger.warn(`redis error: ${err.message}`);
25 });
26 this.client.on("connect", () => logger.info("redis connected"));
27 }
28
29
30 getRedis(): Redis {
31 return this.client;
32 }
33
34
39 async subscribe(channel: string, handler: (message: string) => void): Promise<() => Promise<void>> {
40 const sub = this.client.duplicate();
41 sub.on("error", () => undefined);
42
43
44
45
46
47 await sub.subscribe(channel, handler as never);
48 return async () => {
49 await sub.unsubscribe(channel).catch(() => undefined);
50 sub.disconnect();
51 };
52 }
53
54
55 async ping(): Promise<boolean> {
56 try {
57 return (await this.client.ping()) === "PONG";
58 } catch {
59 return false;
60 }
61 }
62
63 async onModuleDestroy(): Promise<void> {
64 await this.client.quit().catch(() => this.client.disconnect());
65 }
66}
67