reuse connection by plugin

Signed-off-by: eipc16 <pprzemek.312@gmail.com>
This commit is contained in:
eipc16
2024-11-19 17:23:58 +01:00
parent de6f280dfa
commit 48e5ad4496
2 changed files with 28 additions and 20 deletions
@@ -25,15 +25,21 @@ import { CacheManager } from './CacheManager';
// Contrived code because it's hard to spy on a default export
jest.mock('@keyv/redis', () => {
const Actual = jest.requireActual('@keyv/redis');
return jest.fn((...args: any[]) => {
return new Actual(...args);
});
const DefaultConstructor = Actual.default;
return {
...Actual,
__esModule: true,
default: jest.fn((...args: any[]) => new DefaultConstructor(...args)),
};
});
jest.mock('@keyv/memcache', () => {
const Actual = jest.requireActual('@keyv/memcache');
return jest.fn((...args: any[]) => {
return new Actual(...args);
});
const DefaultConstructor = Actual.default;
return {
...Actual,
__esModule: true,
default: jest.fn((...args: any[]) => new DefaultConstructor(...args)),
};
});
describe('CacheManager integration', () => {
@@ -42,7 +48,7 @@ describe('CacheManager integration', () => {
afterEach(jest.clearAllMocks);
it.each(caches.eachSupportedId())(
'only creates one underlying connection, %p',
'only creates one underlying connection per plugin, %p',
async cacheId => {
const { store, connection } = await caches.init(cacheId);
@@ -59,10 +65,10 @@ describe('CacheManager integration', () => {
if (store === 'redis') {
// eslint-disable-next-line jest/no-conditional-expect
expect(KeyvRedis).toHaveBeenCalledTimes(1);
expect(KeyvRedis).toHaveBeenCalledTimes(3);
} else if (store === 'memcache') {
// eslint-disable-next-line jest/no-conditional-expect
expect(KeyvMemcache).toHaveBeenCalledTimes(1);
expect(KeyvMemcache).toHaveBeenCalledTimes(3);
}
},
);
@@ -140,14 +140,15 @@ export class CacheManager {
private createRedisStoreFactory(): StoreFactory {
const KeyvRedis = require('@keyv/redis').default;
let store: typeof KeyvRedis | undefined;
const stores: Record<string, typeof KeyvRedis> = {};
return (pluginId, defaultTtl) => {
if (!store) {
store = new KeyvRedis(this.connection, {
if (!stores[pluginId]) {
stores[pluginId] = new KeyvRedis(this.connection, {
keyPrefixSeparator: ':',
});
// Always provide an error handler to avoid stopping the process
store.on('error', (err: Error) => {
stores[pluginId].on('error', (err: Error) => {
this.logger?.error('Failed to create redis cache client', err);
this.errorHandler?.(err);
});
@@ -155,7 +156,7 @@ export class CacheManager {
return new Keyv({
namespace: pluginId,
ttl: defaultTtl,
store,
store: stores[pluginId],
emitErrors: false,
useKeyPrefix: false,
});
@@ -163,13 +164,14 @@ export class CacheManager {
}
private createMemcacheStoreFactory(): StoreFactory {
const KeyvMemcache = require('@keyv/memcache');
let store: typeof KeyvMemcache | undefined;
const KeyvMemcache = require('@keyv/memcache').default;
const stores: Record<string, typeof KeyvMemcache> = {};
return (pluginId, defaultTtl) => {
if (!store) {
store = new KeyvMemcache(this.connection);
if (!stores[pluginId]) {
stores[pluginId] = new KeyvMemcache(this.connection);
// Always provide an error handler to avoid stopping the process
store.on('error', (err: Error) => {
stores[pluginId].on('error', (err: Error) => {
this.logger?.error('Failed to create memcache cache client', err);
this.errorHandler?.(err);
});
@@ -178,7 +180,7 @@ export class CacheManager {
namespace: pluginId,
ttl: defaultTtl,
emitErrors: false,
store,
store: stores[pluginId],
});
};
}