import { Redis } from 'ioredis'; import { IRedisManager, IRedisConfig, IOptions } from '@libs/types/'; function parseData(data: string | null, options: IOptions): string[] { try { if (!data) { return []; } return JSON.parse(data); } catch (err) { options.logger.error({ message: 'failed to parse redis data value', err, data, }); return []; } } export default class RedisManager implements IRedisManager { private readonly client: Redis; private readonly options: IOptions; private readonly config: IRedisConfig; constructor(config: IRedisConfig, options: IOptions) { this.client = this.createClient(config); this.options = options; this.config = config; this.setupReconnectHandler(); } private createClient(config: IRedisConfig): Redis { return new Redis(config.url, { retryStrategy: (times: number) => { const { delay } = config; this.options.logger.error({ message: `Retry attempt ${times}. Retrying connection after ${delay}ms.`, }); return delay; }, }); } private setupReconnectHandler(): void { this.client.on('connect', () => { this.options.logger.info({ message: 'Connected to Redis server' }); }); this.client.on('error', (err: Error) => { this.options.logger.error({ message: 'Error connecting to Redis', err }); }); this.client.on('close', () => { this.options.logger.info({ message: 'Connection to Redis closed' }); }); this.client.on('end', () => { this.options.logger.info({ message: 'Disconnected from Redis server' }); }); } public async hasFeatureFlag(tenantId: string, ffName: string): Promise { const redisKeys = [ `${this.config.cacheFFKeyTenant}${tenantId}`, `${this.config.cacheGaFeatureKey}`, ]; const [ffTenantCached, ffGACached] = await this.mget(redisKeys); const FeatureFlags = parseData(ffTenantCached, this.options).concat( parseData(ffGACached, this.options), ); return FeatureFlags.includes(ffName); } private async mget(keys: string[]): Promise<(string | null)[]> { try { return this.client.mget(...keys); } catch (err) { this.options.logger.error({ message: 'Redis server error', err, }); return []; } } public async disconnect(): Promise { await this.client.quit(); } }