mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-02-13 21:14:24 +01:00
📡 refactor: MCP Runtime Config Sync with Redis Distributed Locking (#10352)
* 🔄 Refactoring: MCP Runtime Configuration Reload
- PrivateServerConfigs own cache classes (inMemory and Redis).
- Connections staleness detection by comparing (connection.createdAt and config.LastUpdatedAt)
- ConnectionsRepo access Registry instead of in memory config dict and renew stale connections
- MCPManager: adjusted init of ConnectionsRepo (app level)
- UserConnectionManager: renew stale connections
- skipped test, to test "should only clear keys in its own namespace"
- MCPPrivateServerLoader: new component to manage logic of loading / editing private servers on runtime
- PrivateServersLoadStatusCache to track private server cache status
- New unit and integration tests.
Misc:
- add es lint rule to enforce line between class methods
* Fix cluster mode batch update and delete workarround. Fixed unit tests for cluster mode.
* Fix Keyv redis clear cache namespace awareness issue + Integration tests fixes
* chore: address copilot comments
* Fixing rebase issue: removed the mcp config fallback in single getServerConfig method:
- to not to interfere with the logic of the right Tier (APP/USER/Private)
- If userId is null, the getServerConfig should not return configs that are a SharedUser tier and not APP tier
* chore: add dev-staging branch to workflow triggers for backend, cache integration, and ESLint checks
---------
Co-authored-by: Atef Bellaaj <slalom.bellaaj@external.daimlertruck.com>
This commit is contained in:
parent
52e6796635
commit
ac68e629e6
49 changed files with 5244 additions and 257 deletions
27
packages/api/src/cache/cacheFactory.ts
vendored
27
packages/api/src/cache/cacheFactory.ts
vendored
|
|
@ -17,6 +17,7 @@ import type { SendCommandFn } from 'rate-limit-redis';
|
|||
import { keyvRedisClient, ioredisClient } from './redisClients';
|
||||
import { cacheConfig } from './cacheConfig';
|
||||
import { violationFile } from './keyvFiles';
|
||||
import { batchDeleteKeys, scanKeys } from './redisUtils';
|
||||
|
||||
/**
|
||||
* Creates a cache instance using Redis or a fallback store. Suitable for general caching needs.
|
||||
|
|
@ -37,6 +38,32 @@ export const standardCache = (namespace: string, ttl?: number, fallbackStore?: o
|
|||
logger.error(`Cache error in namespace ${namespace}:`, err);
|
||||
});
|
||||
|
||||
// Override clear() to handle namespace-aware deletion
|
||||
// The default Keyv clear() doesn't respect namespace due to the workaround above
|
||||
// Workaround for issue #10487 https://github.com/danny-avila/LibreChat/issues/10487
|
||||
cache.clear = async () => {
|
||||
// Type-safe check for Redis client with scanIterator support
|
||||
if (!keyvRedisClient || !('scanIterator' in keyvRedisClient)) {
|
||||
logger.warn(`Cannot clear namespace ${namespace}: Redis scanIterator not available`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build pattern: globalPrefix::namespace:* or namespace:*
|
||||
const pattern = cacheConfig.REDIS_KEY_PREFIX
|
||||
? `${cacheConfig.REDIS_KEY_PREFIX}${cacheConfig.GLOBAL_PREFIX_SEPARATOR}${namespace}:*`
|
||||
: `${namespace}:*`;
|
||||
|
||||
// Use utility functions for efficient scan and parallel deletion
|
||||
const keysToDelete = await scanKeys(keyvRedisClient, pattern);
|
||||
|
||||
if (keysToDelete.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
await batchDeleteKeys(keyvRedisClient, keysToDelete);
|
||||
logger.debug(`Cleared ${keysToDelete.length} keys from namespace ${namespace}`);
|
||||
};
|
||||
|
||||
return cache;
|
||||
} catch (err) {
|
||||
logger.error(`Failed to create Redis cache for namespace ${namespace}:`, err);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue