diff --git a/.changeset/dar-jag-gar.md b/.changeset/dar-jag-gar.md new file mode 100644 index 0000000000..5989614101 --- /dev/null +++ b/.changeset/dar-jag-gar.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +In-memory cache clients instantiated from the same cache manager now share the same memory space. diff --git a/packages/backend-common/src/cache/CacheManager.test.ts b/packages/backend-common/src/cache/CacheManager.test.ts index fb73687f54..ce5b6f5999 100644 --- a/packages/backend-common/src/cache/CacheManager.test.ts +++ b/packages/backend-common/src/cache/CacheManager.test.ts @@ -147,6 +147,22 @@ describe('CacheManager', () => { }); }); + it('shares memory across multiple instances of the memory client', () => { + const manager = CacheManager.fromConfig(defaultConfig()); + const plugin = 'test-plugin'; + + // Instantiate two in-memory clients. + manager.forPlugin(plugin).getClient({ defaultTtl: 10 }); + manager.forPlugin(plugin).getClient({ defaultTtl: 10 }); + + const cache = Keyv as unknown as jest.Mock; + const mockCall2 = cache.mock.calls.splice(-1)[0][0]; + const mockCall1 = cache.mock.calls.splice(-1)[0][0]; + + // Note: .toBe() checks referential identity of object instances. + expect(mockCall1.store).toBe(mockCall2.store); + }); + it('returns a memcache client when configured', () => { const expectedHost = '127.0.0.1:11211'; const manager = CacheManager.fromConfig( diff --git a/packages/backend-common/src/cache/CacheManager.ts b/packages/backend-common/src/cache/CacheManager.ts index d3a1504187..896c08fb94 100644 --- a/packages/backend-common/src/cache/CacheManager.ts +++ b/packages/backend-common/src/cache/CacheManager.ts @@ -42,6 +42,13 @@ export class CacheManager { none: this.getNoneClient, }; + /** + * Shared memory store for the in-memory cache client. Sharing the same Map + * instance ensures get/set/delete operations hit the same store, regardless + * of where/when a client is instantiated. + */ + private readonly memoryStore = new Map(); + private readonly logger: Logger; private readonly store: keyof CacheManager['storeFactories']; private readonly connection: string; @@ -133,6 +140,7 @@ export class CacheManager { return new Keyv({ namespace: pluginId, ttl: defaultTtl, + store: this.memoryStore, }); }