🗃️ refactor: Separate Tool Cache Namespace for Blue/Green Deployments (#11738)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run

* 🔧 refactor: Introduce TOOL_CACHE for isolated caching of tools

- Added TOOL_CACHE key to CacheKeys enum for managing tool-related cache.
- Updated various services and controllers to utilize TOOL_CACHE instead of CONFIG_STORE for better separation of concerns in caching logic.
- Enhanced .env.example with comments on using in-memory cache for blue/green deployments.

* 🔧 refactor: Update cache configuration for in-memory storage handling

- Enhanced the handling of `FORCED_IN_MEMORY_CACHE_NAMESPACES` in `cacheConfig.ts` to default to `CONFIG_STORE` and `APP_CONFIG`, ensuring safer blue/green deployments.
- Updated `.env.example` with clearer comments regarding the usage of in-memory cache namespaces.
- Improved unit tests to validate the new default behavior and handling of empty strings for cache namespaces.
This commit is contained in:
Danny Avila 2026-02-11 22:20:43 -05:00 committed by GitHub
parent c7531dd029
commit 5b67e48fe1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 284 additions and 18 deletions

View file

@ -8,7 +8,7 @@ const { getLogStores } = require('~/cache');
const getAvailablePluginsController = async (req, res) => {
try {
const cache = getLogStores(CacheKeys.CONFIG_STORE);
const cache = getLogStores(CacheKeys.TOOL_CACHE);
const cachedPlugins = await cache.get(CacheKeys.PLUGINS);
if (cachedPlugins) {
res.status(200).json(cachedPlugins);
@ -63,7 +63,7 @@ const getAvailableTools = async (req, res) => {
logger.warn('[getAvailableTools] User ID not found in request');
return res.status(401).json({ message: 'Unauthorized' });
}
const cache = getLogStores(CacheKeys.CONFIG_STORE);
const cache = getLogStores(CacheKeys.TOOL_CACHE);
const cachedToolsArray = await cache.get(CacheKeys.TOOLS);
const appConfig = req.config ?? (await getAppConfig({ role: req.user?.role }));

View file

@ -1,3 +1,4 @@
const { CacheKeys } = require('librechat-data-provider');
const { getCachedTools, getAppConfig } = require('~/server/services/Config');
const { getLogStores } = require('~/cache');
@ -63,6 +64,28 @@ describe('PluginController', () => {
});
});
describe('cache namespace', () => {
it('getAvailablePluginsController should use TOOL_CACHE namespace', async () => {
mockCache.get.mockResolvedValue([]);
await getAvailablePluginsController(mockReq, mockRes);
expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
});
it('getAvailableTools should use TOOL_CACHE namespace', async () => {
mockCache.get.mockResolvedValue([]);
await getAvailableTools(mockReq, mockRes);
expect(getLogStores).toHaveBeenCalledWith(CacheKeys.TOOL_CACHE);
});
it('should NOT use CONFIG_STORE namespace for tool/plugin operations', async () => {
mockCache.get.mockResolvedValue([]);
await getAvailablePluginsController(mockReq, mockRes);
await getAvailableTools(mockReq, mockRes);
const allCalls = getLogStores.mock.calls.flat();
expect(allCalls).not.toContain(CacheKeys.CONFIG_STORE);
});
});
describe('getAvailablePluginsController', () => {
it('should use filterUniquePlugins to remove duplicate plugins', async () => {
// Add plugins with duplicates to availableTools