225 lines
5.6 KiB
JavaScript
225 lines
5.6 KiB
JavaScript
/**
|
|
* 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
|
|
};
|