Files
a-share-analysis/server/libs/infrastructure/src/redis-health.client.ts

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);
}