import IORedis, { Redis as IOredis } from 'ioredis' export class Redis { private static client: Redis private redis: IOredis private constructor() { this.redis = process.env.REDIS_URI ? new IORedis(process.env.REDIS_URI) : null } public static connect(): Redis { if (!this.client) { this.client = new Redis() } this.client.redis?.on('connect', () => console.log('redis: connected')) this.client.redis?.on('ready', () => console.log('redis: ready')) this.client.redis?.on('error', console.error) return this.client } public async get(key: string): Promise { const result = await this.redis?.get(key) if (!result) return null try { return JSON.parse(result) } catch (error) { return result } } public async set(key: string, data: unknown, ex?: number): Promise { try { if (ex) { return await this.redis?.set(key, JSON.stringify(data), 'EX', ex) === 'OK' } else { return await this.redis?.set(key, JSON.stringify(data)) === 'OK' } } catch (error) { if (ex) { return await this.redis?.set(key, data as any, 'EX', ex) === 'OK' } else { return await this.redis?.set(key, data as any) === 'OK' } } } public async del(key: string): Promise { return await this.redis?.del(key) === 1 } public async getFromCacheFirst(key: string, fn: () => T | Promise, ex?: number): Promise { try { const result = await this.get(key) if (result) return result const data = await fn() await this.set(key, data, ex) return data } catch (error) { return await fn() } } }