61 lines
1.7 KiB
TypeScript
61 lines
1.7 KiB
TypeScript
import Redis from 'ioredis';
|
|
import type { OnModuleDestroy } from '@nestjs/common';
|
|
|
|
import type { DependencyHealthDto } from '../../http-contracts/src/health.dto';
|
|
import type { RedisRuntimeConfig } from '../../config/src/runtime-config';
|
|
|
|
interface RedisPingPort {
|
|
status: string;
|
|
connect(): Promise<void>;
|
|
ping(): Promise<string>;
|
|
quit(): Promise<unknown>;
|
|
}
|
|
|
|
/** Redis 健康客户端只执行连接与 PING,不读写任何业务键。 */
|
|
export class RedisHealthClient implements OnModuleDestroy {
|
|
constructor(private readonly client: RedisPingPort) {}
|
|
|
|
async check(): Promise<DependencyHealthDto> {
|
|
if (
|
|
this.client.status === 'wait' ||
|
|
this.client.status === 'end' ||
|
|
this.client.status === 'close'
|
|
) {
|
|
await this.client.connect();
|
|
}
|
|
const response = await this.client.ping();
|
|
if (response !== 'PONG') throw new Error('Redis PING 未返回 PONG');
|
|
return { status: 'healthy', detail: 'PONG' };
|
|
}
|
|
|
|
async close(): Promise<void> {
|
|
if (
|
|
this.client.status !== 'wait' &&
|
|
this.client.status !== 'end' &&
|
|
this.client.status !== 'close'
|
|
) {
|
|
await this.client.quit();
|
|
}
|
|
}
|
|
|
|
async onModuleDestroy(): Promise<void> {
|
|
await this.close();
|
|
}
|
|
}
|
|
|
|
/** 使用 lazyConnect 创建最小连接池,只有健康请求触发真实连接。 */
|
|
export function createRedisHealthClient(config: RedisRuntimeConfig): RedisHealthClient {
|
|
const client = new Redis({
|
|
host: config.host,
|
|
port: config.port,
|
|
username: config.username || undefined,
|
|
password: config.password || undefined,
|
|
db: config.database,
|
|
tls: config.tls ? {} : undefined,
|
|
lazyConnect: true,
|
|
enableOfflineQueue: false,
|
|
maxRetriesPerRequest: 0,
|
|
});
|
|
return new RedisHealthClient(client);
|
|
}
|