feature/IO-3096-GlobalNotifications - Checkpoint, App Queue

This commit is contained in:
Dave Richer
2025-02-18 17:37:24 -05:00
parent 00005c881e
commit 2a81517104
4 changed files with 190 additions and 189 deletions

View File

@@ -136,75 +136,75 @@ const applyRedisHelpers = ({ pubClient, app, logger }) => {
const addUserSocketMapping = async (email, socketId, bodyshopId) => {
const userKey = `user:${email}`;
const bodyshopKey = `${userKey}:bodyshops:${bodyshopId}`;
const socketMappingKey = `${userKey}:socketMapping`;
try {
logger.log(`Adding socket ${socketId} to user ${email} for bodyshop ${bodyshopId}`, "debug", "redis");
// Mark the bodyshop as associated with the user in the hash
await pubClient.hset(userKey, `bodyshops:${bodyshopId}`, "1");
// Add the socket ID to the bodyshop-specific set
await pubClient.sadd(bodyshopKey, socketId);
// Set TTL to 24 hours for both keys
await pubClient.expire(userKey, 86400);
await pubClient.expire(bodyshopKey, 86400);
// Save the mapping: socketId -> bodyshopId
await pubClient.hset(socketMappingKey, socketId, bodyshopId);
// Set TTL (24 hours) for the mapping hash
await pubClient.expire(socketMappingKey, 86400);
} catch (error) {
logger.log(`Error adding socket mapping for ${email} (bodyshop ${bodyshopId}): ${error}`, "ERROR", "redis");
}
};
const refreshUserSocketTTL = async (email, bodyshopId) => {
const refreshUserSocketTTL = async (email) => {
const userKey = `user:${email}`;
const bodyshopKey = `${userKey}:bodyshops:${bodyshopId}`;
const socketMappingKey = `${userKey}:socketMapping`;
try {
const userExists = await pubClient.exists(userKey);
if (userExists) {
await pubClient.expire(userKey, 86400);
}
const bodyshopExists = await pubClient.exists(bodyshopKey);
if (bodyshopExists) {
await pubClient.expire(bodyshopKey, 86400);
logger.log(`Refreshed TTL for ${email} bodyshop ${bodyshopId} socket mapping`, "debug", "redis");
const exists = await pubClient.exists(socketMappingKey);
if (exists) {
await pubClient.expire(socketMappingKey, 86400);
logger.log(`Refreshed TTL for ${email} socket mapping`, "debug", "redis");
}
} catch (error) {
logger.log(`Error refreshing TTL for ${email} (bodyshop ${bodyshopId}): ${error}`, "ERROR", "redis");
logger.log(`Error refreshing TTL for ${email}: ${error}`, "ERROR", "redis");
}
};
const removeUserSocketMapping = async (email, socketId, bodyshopId) => {
const removeUserSocketMapping = async (email, socketId) => {
const userKey = `user:${email}`;
const bodyshopKey = `${userKey}:bodyshops:${bodyshopId}`;
const socketMappingKey = `${userKey}:socketMapping`;
try {
logger.log(`Removing socket ${socketId} from user ${email} for bodyshop ${bodyshopId}`, "DEBUG", "redis");
await pubClient.srem(bodyshopKey, socketId);
// Refresh TTL if there are still sockets, or let it expire
const remainingSockets = await pubClient.scard(bodyshopKey);
if (remainingSockets > 0) {
await pubClient.expire(bodyshopKey, 86400);
} else {
// Optionally remove the bodyshop field from the hash if no sockets remain
await pubClient.hdel(userKey, `bodyshops:${bodyshopId}`);
logger.log(`Removing socket ${socketId} mapping for user ${email}`, "DEBUG", "redis");
// Look up the bodyshopId associated with this socket
const bodyshopId = await pubClient.hget(socketMappingKey, socketId);
if (!bodyshopId) {
logger.log(`Socket ${socketId} not found for user ${email}`, "DEBUG", "redis");
return;
}
// Refresh user key TTL if there are still bodyshops
const remainingBodyshops = await pubClient.hlen(userKey);
if (remainingBodyshops > 0) {
await pubClient.expire(userKey, 86400);
// Remove the socket mapping
await pubClient.hdel(socketMappingKey, socketId);
logger.log(
`Removed socket ${socketId} (associated with bodyshop ${bodyshopId}) for user ${email}`,
"DEBUG",
"redis"
);
// Refresh TTL if any socket mappings remain
const remainingSockets = await pubClient.hlen(socketMappingKey);
if (remainingSockets > 0) {
await pubClient.expire(socketMappingKey, 86400);
}
} catch (error) {
logger.log(`Error removing socket mapping for ${email} (bodyshop ${bodyshopId}): ${error}`, "ERROR", "redis");
logger.log(`Error removing socket mapping for ${email}: ${error}`, "ERROR", "redis");
}
};
const getUserSocketMapping = async (email) => {
const userKey = `user:${email}`;
const socketMappingKey = `${userKey}:socketMapping`;
try {
// Get all bodyshop fields from the hash
const bodyshops = await pubClient.hkeys(userKey);
// Retrieve all socket mappings for the user
const mapping = await pubClient.hgetall(socketMappingKey);
const ttl = await pubClient.ttl(socketMappingKey);
// Group socket IDs by bodyshopId
const result = {};
for (const bodyshopField of bodyshops) {
const bodyshopId = bodyshopField.split("bodyshops:")[1];
const bodyshopKey = `${userKey}:bodyshops:${bodyshopId}`;
const socketIds = await pubClient.smembers(bodyshopKey);
const ttl = await pubClient.ttl(bodyshopKey);
result[bodyshopId] = { socketIds, ttl };
for (const [socketId, bodyshopId] of Object.entries(mapping)) {
if (!result[bodyshopId]) {
result[bodyshopId] = { socketIds: [], ttl };
}
result[bodyshopId].socketIds.push(socketId);
}
return result;
} catch (error) {