// services/redis-service.mjs import Redis from 'ioredis'; import dotenv from 'dotenv'; import { logger } from '../utils/logger.mjs'; dotenv.config(); const redisUrl = process.env.REDIS_URL; let redisClient; export const ACTIVITY_KEY_PREFIX = 'activity:'; // Exported for use in cache-manager const STAFF_KEY = 'staffs:all'; try { if (redisUrl) { redisClient = new Redis(redisUrl); redisClient.on('connect', () => { logger.info('Connected to Redis successfully!'); }); redisClient.on('error', (err) => { logger.error('Redis connection error:', err); }); } else { logger.error('REDIS_URL not defined. Redis client not initialized.'); } } catch (error) { logger.error('Failed to initialize Redis client:', error); } /** * Gets activity data from Redis. * @param {string} activityId * @returns {Promise} Parsed JSON object or null if not found/error. */ export async function getActivityData(activityId) { if (!redisClient) { logger.warn('Redis client not available, skipping getActivityData'); return null; } try { const data = await redisClient.get(`${ACTIVITY_KEY_PREFIX}${activityId}`); return data ? JSON.parse(data) : null; } catch (err) { logger.error(`Error getting activity ${activityId} from Redis:`, err); return null; } } /** * Sets activity data in Redis. * @param {string} activityId * @param {object} data The activity data object. * @returns {Promise} */ export async function setActivityData(activityId, data) { if (!redisClient) { logger.warn('Redis client not available, skipping setActivityData'); return; } try { await redisClient.set(`${ACTIVITY_KEY_PREFIX}${activityId}`, JSON.stringify(data)); } catch (err) { logger.error(`Error setting activity ${activityId} in Redis:`, err); } } /** * Gets staff data from Redis. * @returns {Promise} Parsed JSON object or null if not found/error. */ export async function getStaffData() { if (!redisClient) { logger.warn('Redis client not available, skipping getStaffData'); return null; } try { const data = await redisClient.get(STAFF_KEY); return data ? JSON.parse(data) : null; } catch (err) { logger.error('Error getting staff data from Redis:', err); return null; } } /** * Sets staff data in Redis. * @param {object} data The staff data object. * @returns {Promise} */ export async function setStaffData(data) { if (!redisClient) { logger.warn('Redis client not available, skipping setStaffData'); return; } try { await redisClient.set(STAFF_KEY, JSON.stringify(data)); } catch (err) { logger.error('Error setting staff data in Redis:', err); } } /** * Gets all activity keys from Redis. * This can be resource-intensive on large datasets. Use with caution. * @returns {Promise} An array of keys. */ export async function getAllActivityKeys() { if (!redisClient) { logger.warn('Redis client not available, skipping getAllActivityKeys'); return []; } try { // Using SCAN for better performance than KEYS on production Redis let cursor = '0'; const keys = []; do { const [nextCursor, foundKeys] = await redisClient.scan(cursor, 'MATCH', `${ACTIVITY_KEY_PREFIX}*`, 'COUNT', '100'); keys.push(...foundKeys); cursor = nextCursor; } while (cursor !== '0'); logger.info(`Found ${keys.length} activity keys in Redis using SCAN.`); return keys; } catch (err) { logger.error('Error getting all activity keys from Redis using SCAN:', err); return []; // Fallback or indicate error } } export function getRedisClient() { return redisClient; }