From b81c7dfb8a99ba28d9229d8e452e4e75e952d3c1 Mon Sep 17 00:00:00 2001 From: AlecM33 Date: Sat, 21 Jan 2023 16:25:21 -0500 Subject: [PATCH] remove unnecessary redis client, set up dynamic redis connection --- index.js | 10 +-- server/api/AdminAPI.js | 4 +- server/modules/singletons/EventManager.js | 104 +++++++++++++--------- server/modules/singletons/GameManager.js | 10 +-- 4 files changed, 70 insertions(+), 58 deletions(-) diff --git a/index.js b/index.js index 56067f3..4099846 100644 --- a/index.js +++ b/index.js @@ -32,15 +32,9 @@ singletons.eventManager.timerManager = timerManager.instance; singletons.eventManager.gameManager = GameManager.instance; - try { - await singletons.eventManager.client.connect(); - logger.info('Root Redis client connected'); - } catch(e) { - reject(new Error('UNABLE TO CONNECT TO REDIS because: '+ e)); - } - - await singletons.eventManager.createGameSyncSubscriber(singletons.gameManager, singletons.eventManager); await singletons.eventManager.createRedisPublisher(); + await singletons.eventManager.createGameSyncSubscriber(singletons.gameManager, singletons.eventManager); + const socketServer = singletons.eventManager.createSocketServer(webServer, app, port); singletons.gameManager.setGameSocketNamespace(singletons.eventManager.createGameSocketNamespace(socketServer, logger, singletons.gameManager)); diff --git a/server/api/AdminAPI.js b/server/api/AdminAPI.js index 2f20445..8a2a96b 100644 --- a/server/api/AdminAPI.js +++ b/server/api/AdminAPI.js @@ -21,8 +21,8 @@ router.post('/sockets/broadcast', function (req, res) { router.get('/games/state', async (req, res) => { const gamesArray = []; - const keys = await eventManager.client.keys('*'); - const values = await eventManager.client.mGet(keys); + const keys = await eventManager.publisher.keys('*'); + const values = await eventManager.publisher.mGet(keys); values.forEach((v) => { let parsedGame; try { diff --git a/server/modules/singletons/EventManager.js b/server/modules/singletons/EventManager.js index 9cba5a6..a84c977 100644 --- a/server/modules/singletons/EventManager.js +++ b/server/modules/singletons/EventManager.js @@ -10,7 +10,6 @@ class EventManager { } logger.info('CREATING SINGLETON EVENT MANAGER'); this.logger = logger; - this.client = redis.createClient(); this.io = null; this.publisher = null; this.subscriber = null; @@ -24,56 +23,75 @@ class EventManager { this.io?.emit(globals.EVENTS.BROADCAST, message); }; - createRedisPublisher = async () => { - this.publisher = redis.createClient(); - this.publisher.on('error', (e) => { - this.logger.error('REDIS PUBLISHER CLIENT ERROR:', e); + createRedisPublisher = () => { + return new Promise((resolve, reject) => { + this.publisher = process.env.NODE_ENV.trim() === 'development' + ? redis.createClient() + : redis.createClient({ + url: process.env.REDIS_URL + }); + this.publisher.on('error', (e) => { + this.logger.error('REDIS PUBLISHER CLIENT ERROR:', e); + }); + try { + this.publisher.connect(); + resolve(); + } catch (e) { + reject(new Error('UNABLE TO CONNECT TO REDIS because: ' + e)); + } + this.logger.info('EVENT MANAGER - CREATED PUBLISHER'); }); - await this.publisher.connect(); - this.logger.info('EVENT MANAGER - CREATED PUBLISHER'); } - createGameSyncSubscriber = async (gameManager, eventManager) => { - this.subscriber = this.client.duplicate(); - this.subscriber.on('error', (e) => { - this.logger.error('REDIS SUBSCRIBER CLIENT ERROR:', e); - }); - await this.subscriber.connect(); - await this.subscriber.subscribe(globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM, async (message) => { - this.logger.debug('MESSAGE: ' + message); - let messageComponents, args; + createGameSyncSubscriber = (gameManager, eventManager) => { + return new Promise((resolve, reject) => { + this.subscriber = this.publisher.duplicate(); + this.subscriber.on('error', (e) => { + this.logger.error('REDIS SUBSCRIBER CLIENT ERROR:', e); + }); try { - messageComponents = message.split(';', 3); - if (messageComponents[messageComponents.length - 1] === this.instanceId) { - this.logger.trace('Disregarding self-authored message'); + this.subscriber.connect(); + resolve(); + this.logger.info('EVENT MANAGER - CREATED SUBSCRIBER'); + } catch (e) { + reject(new Error('UNABLE TO CONNECT TO REDIS because: ' + e)); + } + + this.subscriber.subscribe(globals.REDIS_CHANNELS.ACTIVE_GAME_STREAM, async (message) => { + this.logger.debug('MESSAGE: ' + message); + let messageComponents, args; + try { + messageComponents = message.split(';', 3); + if (messageComponents[messageComponents.length - 1] === this.instanceId) { + this.logger.trace('Disregarding self-authored message'); + return; + } + args = JSON.parse( + message.slice( + message.indexOf(messageComponents[messageComponents.length - 1]) + (globals.INSTANCE_ID_LENGTH + 1) + ) + ); + } catch (e) { + this.logger.error('MALFORMED MESSAGE RESULTED IN ERROR: ' + e + '; DISREGARDING'); return; } - args = JSON.parse( - message.slice( - message.indexOf(messageComponents[messageComponents.length - 1]) + (globals.INSTANCE_ID_LENGTH + 1) - ) - ); - } catch (e) { - this.logger.error('MALFORMED MESSAGE RESULTED IN ERROR: ' + e + '; DISREGARDING'); - return; - } - if (messageComponents) { - const game = await gameManager.getActiveGame(messageComponents[0]); - if (game) { - await eventManager.handleEventById( - messageComponents[1], - messageComponents[messageComponents.length - 1], - game, - null, - game?.accessCode || messageComponents[0], - args || null, - null, - true - ); + if (messageComponents) { + const game = await gameManager.getActiveGame(messageComponents[0]); + if (game) { + await eventManager.handleEventById( + messageComponents[1], + messageComponents[messageComponents.length - 1], + game, + null, + game?.accessCode || messageComponents[0], + args || null, + null, + true + ); + } } - } + }); }); - this.logger.info('EVENT MANAGER - CREATED SUBSCRIBER'); } createMessageToPublish = (...args) => { diff --git a/server/modules/singletons/GameManager.js b/server/modules/singletons/GameManager.js index 6ede4d5..2aa1cc5 100644 --- a/server/modules/singletons/GameManager.js +++ b/server/modules/singletons/GameManager.js @@ -21,7 +21,7 @@ class GameManager { } getActiveGame = async (accessCode) => { - const r = await this.eventManager.client.get(accessCode); + const r = await this.eventManager.publisher.get(accessCode); if (r === null && this.timerManager.timerThreads[accessCode]) { if (!this.timerManager.timerThreads[accessCode].killed) { this.timerManager.timerThreads[accessCode].kill(); @@ -45,7 +45,7 @@ class GameManager { refreshGame = async (game) => { this.logger.debug('PUSHING REFRESH OF ' + game.accessCode); - await this.eventManager.client.set(game.accessCode, JSON.stringify(game), { + await this.eventManager.publisher.set(game.accessCode, JSON.stringify(game), { KEEPTTL: true, XX: true // only set the key if it already exists }); @@ -85,7 +85,7 @@ class GameManager { new Date().toJSON(), req.timerParams ); - await this.eventManager.client.set(newAccessCode, JSON.stringify(newGame), { + await this.eventManager.publisher.set(newAccessCode, JSON.stringify(newGame), { EX: globals.STALE_GAME_SECONDS }); return Promise.resolve({ accessCode: newAccessCode, cookie: moderator.cookie, environment: this.environment }); @@ -151,7 +151,7 @@ class GameManager { const charCount = charPool.length; let codeDigits, accessCode; let attempts = 0; - while (!accessCode || ((await this.eventManager.client.keys('*')).includes(accessCode) + while (!accessCode || ((await this.eventManager.publisher.keys('*')).includes(accessCode) && attempts < globals.ACCESS_CODE_GENERATION_ATTEMPTS)) { codeDigits = []; let iterations = globals.ACCESS_CODE_LENGTH; @@ -162,7 +162,7 @@ class GameManager { accessCode = codeDigits.join(''); attempts ++; } - return (await this.eventManager.client.keys('*')).includes(accessCode) + return (await this.eventManager.publisher.keys('*')).includes(accessCode) ? null : accessCode; };