/** * Redis Client - опциональное подключение * Если Redis недоступен, работает без БД */ let redisClient = null; let redisAvailable = false; let redisClientInstance = null; // Для connect-redis async function initRedis() { // Проверяем, нужно ли использовать Redis const useRedis = process.env.USE_REDIS === 'true' || process.env.REDIS_URL; if (!useRedis) { console.log('📦 Redis отключен (USE_REDIS=false или REDIS_URL не установлен)'); return; } try { const redis = require('redis'); const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379'; redisClient = redis.createClient({ url: redisUrl, socket: { reconnectStrategy: (retries) => { if (retries > 10) { console.log('⚠️ Redis: слишком много попыток переподключения, отключаемся'); redisAvailable = false; return false; // Остановить переподключение } return Math.min(retries * 100, 3000); } } }); redisClient.on('error', (err) => { console.error('❌ Redis ошибка:', err.message); redisAvailable = false; }); redisClient.on('connect', () => { console.log('🔌 Redis: подключение установлено'); redisAvailable = true; }); redisClient.on('ready', () => { console.log('✅ Redis: готов к работе'); redisAvailable = true; }); redisClient.on('end', () => { console.log('🔌 Redis: соединение закрыто'); redisAvailable = false; }); await redisClient.connect(); redisClientInstance = redisClient; // Сохраняем для connect-redis redisAvailable = true; console.log('✅ Redis подключен успешно'); // Экспортируем клиент для connect-redis module.exports.redisClientInstance = redisClient; } catch (error) { console.warn('⚠️ Redis недоступен, работаем без БД:', error.message); redisAvailable = false; redisClient = null; } } async function closeRedis() { if (redisClient && redisAvailable) { try { await redisClient.quit(); console.log('🔌 Redis: соединение закрыто'); } catch (error) { console.error('Ошибка при закрытии Redis:', error); } } } // Проверка доступности Redis function isRedisAvailable() { return redisAvailable && redisClient !== null; } // Получить значение async function get(key) { if (!isRedisAvailable()) return null; try { return await redisClient.get(key); } catch (error) { console.error('Redis get error:', error); return null; } } // Установить значение async function set(key, value, expireSeconds = null) { if (!isRedisAvailable()) return false; try { if (expireSeconds) { await redisClient.setEx(key, expireSeconds, value); } else { await redisClient.set(key, value); } return true; } catch (error) { console.error('Redis set error:', error); return false; } } // Удалить ключ async function del(key) { if (!isRedisAvailable()) return false; try { await redisClient.del(key); return true; } catch (error) { console.error('Redis del error:', error); return false; } } // Получить все ключи по паттерну async function keys(pattern) { if (!isRedisAvailable()) return []; try { return await redisClient.keys(pattern); } catch (error) { console.error('Redis keys error:', error); return []; } } // Получить хеш async function hGet(key, field) { if (!isRedisAvailable()) return null; try { return await redisClient.hGet(key, field); } catch (error) { console.error('Redis hGet error:', error); return null; } } // Установить поле в хеше async function hSet(key, field, value) { if (!isRedisAvailable()) return false; try { await redisClient.hSet(key, field, value); return true; } catch (error) { console.error('Redis hSet error:', error); return false; } } // Получить все поля хеша async function hGetAll(key) { if (!isRedisAvailable()) return {}; try { return await redisClient.hGetAll(key); } catch (error) { console.error('Redis hGetAll error:', error); return {}; } } // Увеличить значение async function incr(key) { if (!isRedisAvailable()) return 0; try { return await redisClient.incr(key); } catch (error) { console.error('Redis incr error:', error); return 0; } } // Получить список (добавить в конец) async function rPush(key, ...values) { if (!isRedisAvailable()) return 0; try { return await redisClient.rPush(key, values); } catch (error) { console.error('Redis rPush error:', error); return 0; } } // Получить элементы списка async function lRange(key, start, stop) { if (!isRedisAvailable()) return []; try { return await redisClient.lRange(key, start, stop); } catch (error) { console.error('Redis lRange error:', error); return []; } } // Получить клиент Redis для connect-redis function getRedisClient() { return redisClientInstance; } module.exports = { initRedis, closeRedis, isRedisAvailable, getRedisClient, get, set, del, keys, hGet, hSet, hGetAll, incr, rPush, lRange };