mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 06:00:56 +02:00

* ✨ feat: Enhance Redis Config and Error Handling
- Added new Redis configuration options: `REDIS_RETRY_MAX_DELAY`, `REDIS_RETRY_MAX_ATTEMPTS`, `REDIS_CONNECT_TIMEOUT`, and `REDIS_ENABLE_OFFLINE_QUEUE` to improve connection resilience.
- Implemented error handling for Redis cache creation and session store initialization in `cacheFactory.js`.
- Enhanced logging for Redis client events and errors in `redisClients.js`.
- Updated `README.md` to document new Redis configuration options.
* chore: Add JSDoc comments to Redis configuration options in cacheConfig.js for improved clarity and documentation
* ci: update cacheFactory tests
* refactor: remove fallback
* fix: Improve error handling in Redis cache creation, re-throw errors when expected
62 lines
2.8 KiB
JavaScript
62 lines
2.8 KiB
JavaScript
const fs = require('fs');
|
|
const { math, isEnabled } = require('@librechat/api');
|
|
const { CacheKeys } = require('librechat-data-provider');
|
|
|
|
// To ensure that different deployments do not interfere with each other's cache, we use a prefix for the Redis keys.
|
|
// This prefix is usually the deployment ID, which is often passed to the container or pod as an env var.
|
|
// Set REDIS_KEY_PREFIX_VAR to the env var that contains the deployment ID.
|
|
const REDIS_KEY_PREFIX_VAR = process.env.REDIS_KEY_PREFIX_VAR;
|
|
const REDIS_KEY_PREFIX = process.env.REDIS_KEY_PREFIX;
|
|
if (REDIS_KEY_PREFIX_VAR && REDIS_KEY_PREFIX) {
|
|
throw new Error('Only either REDIS_KEY_PREFIX_VAR or REDIS_KEY_PREFIX can be set.');
|
|
}
|
|
|
|
const USE_REDIS = isEnabled(process.env.USE_REDIS);
|
|
if (USE_REDIS && !process.env.REDIS_URI) {
|
|
throw new Error('USE_REDIS is enabled but REDIS_URI is not set.');
|
|
}
|
|
|
|
// Comma-separated list of cache namespaces that should be forced to use in-memory storage
|
|
// even when Redis is enabled. This allows selective performance optimization for specific caches.
|
|
const FORCED_IN_MEMORY_CACHE_NAMESPACES = process.env.FORCED_IN_MEMORY_CACHE_NAMESPACES
|
|
? process.env.FORCED_IN_MEMORY_CACHE_NAMESPACES.split(',').map((key) => key.trim())
|
|
: [];
|
|
|
|
// Validate against CacheKeys enum
|
|
if (FORCED_IN_MEMORY_CACHE_NAMESPACES.length > 0) {
|
|
const validKeys = Object.values(CacheKeys);
|
|
const invalidKeys = FORCED_IN_MEMORY_CACHE_NAMESPACES.filter((key) => !validKeys.includes(key));
|
|
|
|
if (invalidKeys.length > 0) {
|
|
throw new Error(
|
|
`Invalid cache keys in FORCED_IN_MEMORY_CACHE_NAMESPACES: ${invalidKeys.join(', ')}. Valid keys: ${validKeys.join(', ')}`,
|
|
);
|
|
}
|
|
}
|
|
|
|
const cacheConfig = {
|
|
FORCED_IN_MEMORY_CACHE_NAMESPACES,
|
|
USE_REDIS,
|
|
REDIS_URI: process.env.REDIS_URI,
|
|
REDIS_USERNAME: process.env.REDIS_USERNAME,
|
|
REDIS_PASSWORD: process.env.REDIS_PASSWORD,
|
|
REDIS_CA: process.env.REDIS_CA ? fs.readFileSync(process.env.REDIS_CA, 'utf8') : null,
|
|
REDIS_KEY_PREFIX: process.env[REDIS_KEY_PREFIX_VAR] || REDIS_KEY_PREFIX || '',
|
|
REDIS_MAX_LISTENERS: math(process.env.REDIS_MAX_LISTENERS, 40),
|
|
REDIS_PING_INTERVAL: math(process.env.REDIS_PING_INTERVAL, 0),
|
|
/** Max delay between reconnection attempts in ms */
|
|
REDIS_RETRY_MAX_DELAY: math(process.env.REDIS_RETRY_MAX_DELAY, 3000),
|
|
/** Max number of reconnection attempts (0 = infinite) */
|
|
REDIS_RETRY_MAX_ATTEMPTS: math(process.env.REDIS_RETRY_MAX_ATTEMPTS, 10),
|
|
/** Connection timeout in ms */
|
|
REDIS_CONNECT_TIMEOUT: math(process.env.REDIS_CONNECT_TIMEOUT, 10000),
|
|
/** Queue commands when disconnected */
|
|
REDIS_ENABLE_OFFLINE_QUEUE: isEnabled(process.env.REDIS_ENABLE_OFFLINE_QUEUE ?? 'true'),
|
|
|
|
CI: isEnabled(process.env.CI),
|
|
DEBUG_MEMORY_CACHE: isEnabled(process.env.DEBUG_MEMORY_CACHE),
|
|
|
|
BAN_DURATION: math(process.env.BAN_DURATION, 7200000), // 2 hours
|
|
};
|
|
|
|
module.exports = { cacheConfig };
|