From cef3ccd72504539ff3f2303889247a6fb2c81210 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 13 Dec 2023 19:17:10 +0300 Subject: [PATCH] feat: add improvements for handling redis errors --- template/apps/api/src/app.ts | 16 ++++++++++++---- template/apps/api/src/io-emitter.ts | 16 +++++++--------- template/apps/api/src/redis-client.ts | 12 +++++++----- .../api/src/services/socket/socket.service.ts | 4 +++- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/template/apps/api/src/app.ts b/template/apps/api/src/app.ts index 840b4cc1..13dab95c 100644 --- a/template/apps/api/src/app.ts +++ b/template/apps/api/src/app.ts @@ -21,6 +21,8 @@ import { socketService } from 'services'; import config from 'config'; import logger from 'logger'; import routes from 'routes'; + +import { redisErrorHandler } from 'redis-client'; import ioEmitter from 'io-emitter'; const initKoa = () => { @@ -49,10 +51,16 @@ const app = initKoa(); (async () => { const server = http.createServer(app.callback()); - await Promise.all([ - ioEmitter.initClient(), - socketService(server), - ]); + if (config.REDIS_URI) { + try { + await Promise.all([ + ioEmitter.initClient(), + socketService(server), + ]); + } catch (e) { + if (e instanceof Error) redisErrorHandler(e); + } + } server.listen(config.PORT, () => { logger.info(`API server is listening on ${config.PORT}, in ${config.APP_ENV} environment`); diff --git a/template/apps/api/src/io-emitter.ts b/template/apps/api/src/io-emitter.ts index 9a97c245..e926e7b7 100644 --- a/template/apps/api/src/io-emitter.ts +++ b/template/apps/api/src/io-emitter.ts @@ -1,20 +1,15 @@ import { Emitter } from '@socket.io/redis-emitter'; -import redisClient from 'redis-client'; +import redisClient, { redisErrorHandler } from 'redis-client'; import logger from 'logger'; -import config from './config'; - let emitter: Emitter | null = null; const publish = (roomId: string | string[], eventName: string, data: unknown) => { if (emitter === null) { - if (config.REDIS_ERRORS_POLICY === 'throw') { - throw new Error('ioEmitter is not initialized.'); - } else { - logger.debug('ioEmitter is not initialized.'); - return; - } + redisErrorHandler(new Error('ioEmitter is not initialized.')); + + return; } logger.debug(`published io event [${eventName}] to ${roomId}, the data is: ${JSON.stringify(data)}`); @@ -24,6 +19,9 @@ const publish = (roomId: string | string[], eventName: string, data: unknown) => const initClient = async () => { const subClient = redisClient.duplicate(); + + subClient.on('error', redisErrorHandler); + await subClient.connect(); emitter = new Emitter(subClient); diff --git a/template/apps/api/src/redis-client.ts b/template/apps/api/src/redis-client.ts index 16cd74a9..ba62411c 100644 --- a/template/apps/api/src/redis-client.ts +++ b/template/apps/api/src/redis-client.ts @@ -10,21 +10,23 @@ const client = createClient({ connectTimeout: 30_000, reconnectStrategy: (retries) => { const maxDelay = 5_000; - const baseDelay = 50; + const baseDelay = 1_000; return Math.min(baseDelay * Math.pow(2, retries), maxDelay); }, }, }); -client.on('error', err => { - const errorMessage = `redisClient => Redis error: ${err.stack || err}`; +export const redisErrorHandler = (error: Error) => { + const errorMessage = `[Redis Client] ${error.stack || error}`; if (config.REDIS_ERRORS_POLICY === 'throw') { - throw Error(errorMessage); + throw new Error(errorMessage); } else { logger.error(errorMessage); } -}); +}; + +client.on('error', redisErrorHandler); export default client; diff --git a/template/apps/api/src/services/socket/socket.service.ts b/template/apps/api/src/services/socket/socket.service.ts index 40fff891..d8b09c71 100644 --- a/template/apps/api/src/services/socket/socket.service.ts +++ b/template/apps/api/src/services/socket/socket.service.ts @@ -6,7 +6,7 @@ import { COOKIES } from 'app-constants'; import { tokenService } from 'resources/token'; -import pubClient from 'redis-client'; +import pubClient, { redisErrorHandler } from 'redis-client'; import logger from 'logger'; import socketHelper from './socket.helper'; @@ -16,6 +16,8 @@ export default async (server: http.Server) => { const subClient = pubClient.duplicate(); + subClient.on('error', redisErrorHandler); + await Promise.all([pubClient.connect(), subClient.connect()]); logger.info('Socket.io server has been connected.');