From d705f8211e737deb2f8e0c3bdf6ee37fec136b0f Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Fri, 27 Sep 2024 14:52:38 -0400 Subject: [PATCH] feature/IO-2967-Better-Refetch-Handling - Bug fixes and hardening Signed-off-by: Dave Richer --- server.js | 8 +-- server/utils/redisHelpers.js | 91 ++++++++++++++++--------- server/web-sockets/redisSocketEvents.js | 13 ++-- 3 files changed, 64 insertions(+), 48 deletions(-) diff --git a/server.js b/server.js index f7d05bb6b..2b3f8b06b 100644 --- a/server.js +++ b/server.js @@ -192,7 +192,7 @@ const main = async () => { const server = http.createServer(app); const { pubClient, ioRedis } = await applySocketIO(server, app); - const api = applyRedisHelpers(pubClient, app); + const api = applyRedisHelpers(pubClient, app, logger); const ioHelpers = applyIOHelpers(app, api, ioRedis, logger); // Legacy Socket Events @@ -211,11 +211,9 @@ const main = async () => { }; // Start server -try { - main(); -} catch (error) { +main().catch((error) => { logger.log(`Main-API-Error: Something was not caught in the application.`, "error", "api", null, { error: error.message, errorjson: JSON.stringify(error) }); -} +}); diff --git a/server/utils/redisHelpers.js b/server/utils/redisHelpers.js index df2c10303..99801000b 100644 --- a/server/utils/redisHelpers.js +++ b/server/utils/redisHelpers.js @@ -1,48 +1,71 @@ +const logger = require("./logger"); /** * Apply Redis helper functions * @param pubClient * @param app */ -const applyRedisHelpers = (pubClient, app) => { +const applyRedisHelpers = (pubClient, app, logger) => { // Store session data in Redis const setSessionData = async (socketId, key, value) => { - await pubClient.hSet(`socket:${socketId}`, key, JSON.stringify(value)); // Use Redis pubClient + try { + await pubClient.hSet(`socket:${socketId}`, key, JSON.stringify(value)); // Use Redis pubClient + } catch (error) { + logger.log(`Error Setting Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); + } }; // Retrieve session data from Redis const getSessionData = async (socketId, key) => { - const data = await pubClient.hGet(`socket:${socketId}`, key); - return data ? JSON.parse(data) : null; + try { + const data = await pubClient.hGet(`socket:${socketId}`, key); + return data ? JSON.parse(data) : null; + } catch (error) { + logger.log(`Error Getting Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); + } }; // Clear session data from Redis const clearSessionData = async (socketId) => { - await pubClient.del(`socket:${socketId}`); + try { + await pubClient.del(`socket:${socketId}`); + } catch (error) { + logger.log(`Error Clearing Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); + } }; // Store multiple session data in Redis const setMultipleSessionData = async (socketId, keyValues) => { - // keyValues is expected to be an object { key1: value1, key2: value2, ... } - const entries = Object.entries(keyValues).map(([key, value]) => [key, JSON.stringify(value)]); - await pubClient.hSet(`socket:${socketId}`, ...entries.flat()); + try { + // keyValues is expected to be an object { key1: value1, key2: value2, ... } + const entries = Object.entries(keyValues).map(([key, value]) => [key, JSON.stringify(value)]); + await pubClient.hSet(`socket:${socketId}`, ...entries.flat()); + } catch (error) { + logger.log(`Error Setting Multiple Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); + } }; // Retrieve multiple session data from Redis const getMultipleSessionData = async (socketId, keys) => { - const data = await pubClient.hmGet(`socket:${socketId}`, keys); - // Redis returns an object with null values for missing keys, so we parse the non-null ones - return Object.fromEntries(keys.map((key, index) => [key, data[index] ? JSON.parse(data[index]) : null])); + try { + const data = await pubClient.hmGet(`socket:${socketId}`, keys); + // Redis returns an object with null values for missing keys, so we parse the non-null ones + return Object.fromEntries(keys.map((key, index) => [key, data[index] ? JSON.parse(data[index]) : null])); + } catch (error) { + logger.log(`Error Getting Multiple Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); + } }; const setMultipleFromArraySessionData = async (socketId, keyValueArray) => { - // Use Redis multi/pipeline to batch the commands - const multi = pubClient.multi(); - - keyValueArray.forEach(([key, value]) => { - multi.hSet(`socket:${socketId}`, key, JSON.stringify(value)); - }); - - await multi.exec(); // Execute all queued commands + try { + // Use Redis multi/pipeline to batch the commands + const multi = pubClient.multi(); + keyValueArray.forEach(([key, value]) => { + multi.hSet(`socket:${socketId}`, key, JSON.stringify(value)); + }); + await multi.exec(); // Execute all queued commands + } catch (error) { + logger.log(`Error Setting Multiple Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); + } }; // Helper function to add an item to the end of the Redis list @@ -50,7 +73,7 @@ const applyRedisHelpers = (pubClient, app) => { try { await pubClient.rPush(`socket:${socketId}:${key}`, JSON.stringify(newItem)); } catch (error) { - console.error(`Error adding item to the end of the list for socket ${socketId}:`, error); + logger.log(`Error adding item to the end of the list for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; @@ -59,7 +82,7 @@ const applyRedisHelpers = (pubClient, app) => { try { await pubClient.lPush(`socket:${socketId}:${key}`, JSON.stringify(newItem)); } catch (error) { - console.error(`Error adding item to the beginning of the list for socket ${socketId}:`, error); + logger.log(`Error adding item to the beginning of the list for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; @@ -68,33 +91,33 @@ const applyRedisHelpers = (pubClient, app) => { try { await pubClient.del(`socket:${socketId}:${key}`); } catch (error) { - console.error(`Error clearing list for socket ${socketId}:`, error); + logger.log(`Error clearing list for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Add methods to manage room users - const addUserToRoom = async (bodyshopUUID, user) => { + const addUserToRoom = async (room, user) => { try { - await pubClient.sAdd(`bodyshopRoom:${bodyshopUUID}`, JSON.stringify(user)); - } catch (err) { - console.error(`Error adding user to room: ${bodyshopUUID}`); + await pubClient.sAdd(room, JSON.stringify(user)); + } catch (error) { + logger.log(`Error adding user to room ${room}: ${error}`, "ERROR", "redis"); } }; - const removeUserFromRoom = async (bodyshopUUID, user) => { + const removeUserFromRoom = async (room, user) => { try { - await pubClient.sRem(`bodyshopRoom:${bodyshopUUID}`, JSON.stringify(user)); - } catch (err) { - console.error(`Error remove user from room: ${bodyshopUUID}`); + await pubClient.sRem(room, JSON.stringify(user)); + } catch (error) { + logger.log(`Error removing user to room ${room}: ${error}`, "ERROR", "redis"); } }; - const getUsersInRoom = async (bodyshopUUID) => { + const getUsersInRoom = async (room) => { try { - const users = await pubClient.sMembers(`bodyshopRoom:${bodyshopUUID}`); + const users = await pubClient.sMembers(room); return users.map((user) => JSON.parse(user)); - } catch (err) { - console.error(`Error getUsersInRoom: ${bodyshopUUID}`); + } catch (error) { + logger.log(`Error getting users in room ${room}: ${error}`, "ERROR", "redis"); } }; diff --git a/server/web-sockets/redisSocketEvents.js b/server/web-sockets/redisSocketEvents.js index eb107f75e..5cda88569 100644 --- a/server/web-sockets/redisSocketEvents.js +++ b/server/web-sockets/redisSocketEvents.js @@ -33,8 +33,8 @@ const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRo try { const room = getBodyshopRoom(bodyshopUUID); socket.join(room); - await addUserToRoom(room, { uid: socket.user.uid, email: socket.user.email }); - createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${bodyshopUUID}`); + await addUserToRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); + createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${room}`); // Notify all users in the room about the updated user list const usersInRoom = await getUsersInRoom(room); @@ -79,13 +79,8 @@ const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRo // Get all rooms the socket is part of const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); - - for (const bodyshopRoom of rooms) { - await removeUserFromRoom(bodyshopRoom, { uid: socket.user.uid, email: socket.user.email }); - - // Notify all users in the room about the updated user list - const usersInRoom = await getUsersInRoom(bodyshopRoom); - io.to(bodyshopRoom).emit("room-users-updated", usersInRoom); + for (const room of rooms) { + await removeUserFromRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); } } catch (error) { createLogEvent(socket, "ERROR", `Error getting room: ${error}`);