diff --git a/app-config.yaml b/app-config.yaml index 8224b2fb6a..3c4f2d7ea5 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -26,8 +26,6 @@ backend: baseUrl: http://localhost:7000 listen: port: 7000 - cache: - store: memory database: client: sqlite3 connection: ':memory:' diff --git a/packages/backend-common/src/cache/CacheManager.test.ts b/packages/backend-common/src/cache/CacheManager.test.ts index 558964b55c..153ccfd7ac 100644 --- a/packages/backend-common/src/cache/CacheManager.test.ts +++ b/packages/backend-common/src/cache/CacheManager.test.ts @@ -20,6 +20,7 @@ import Keyv from 'keyv'; import KeyvMemcache from 'keyv-memcache'; import { DefaultCacheClient } from './CacheClient'; import { CacheManager } from './CacheManager'; +import { NoStore } from './NoStore'; jest.createMockFromModule('keyv'); jest.mock('keyv'); @@ -104,21 +105,17 @@ describe('CacheManager', () => { }); describe('CacheManager.forPlugin stores', () => { - it('returns memory client when no cache is configured', () => { + it('returns none client when no cache is configured', () => { const manager = CacheManager.fromConfig( new ConfigReader({ backend: {} }), ); - const expectedTtl = 3600; const expectedNamespace = 'test-plugin'; - manager.forPlugin(expectedNamespace).getClient({ defaultTtl: expectedTtl }); + manager.forPlugin(expectedNamespace).getClient(); const cache = Keyv as unknown as jest.Mock; const mockCalls = cache.mock.calls.splice(-1); const callArgs = mockCalls[0]; - expect(callArgs[0]).toMatchObject({ - ttl: expectedTtl, - namespace: expectedNamespace, - }); + expect(callArgs[0].store).toBeInstanceOf(NoStore); }); it('returns memory client when explicitly configured', () => { @@ -156,6 +153,7 @@ describe('CacheManager', () => { expect(mockCacheCalls[0][0]).toMatchObject({ ttl: expectedTtl, }); + expect(mockCacheCalls[0][0].store).toBeInstanceOf(KeyvMemcache); const memcache = KeyvMemcache as jest.Mock; const mockMemcacheCalls = memcache.mock.calls.splice(-1); expect(mockMemcacheCalls[0][0]).toEqual(expectedHost); diff --git a/packages/backend-common/src/cache/CacheManager.ts b/packages/backend-common/src/cache/CacheManager.ts index 00c4cebf18..967ff4224b 100644 --- a/packages/backend-common/src/cache/CacheManager.ts +++ b/packages/backend-common/src/cache/CacheManager.ts @@ -19,11 +19,12 @@ import Keyv from 'keyv'; // @ts-expect-error import KeyvMemcache from 'keyv-memcache'; import { DefaultCacheClient, CacheClient } from './CacheClient'; +import { NoStore } from './NoStore'; import { PluginCacheManager } from './types'; /** * Implements a Cache Manager which will automatically create new cache clients - * for plugins when requested. All requested cacheclients are created with the + * for plugins when requested. All requested cache clients are created with the * connection details provided. */ export class CacheManager { @@ -34,6 +35,7 @@ export class CacheManager { private readonly storeFactories = { memcache: this.getMemcacheClient, memory: this.getMemoryClient, + none: this.getNoneClient, }; private readonly store: keyof CacheManager['storeFactories']; @@ -47,8 +49,8 @@ export class CacheManager { */ static fromConfig(config: Config): CacheManager { // If no `backend.cache` config is provided, instantiate the CacheManager - // with a "memory" cache client. - const store = config.getOptionalString('backend.cache.store') || 'memory'; + // with a "NoStore" cache client. + const store = config.getOptionalString('backend.cache.store') || 'none'; const connectionString = config.getOptionalString('backend.cache.connection') || ''; return new CacheManager(store, connectionString); } @@ -82,11 +84,10 @@ export class CacheManager { } private getMemcacheClient(pluginId: string, defaultTtl: number | undefined): Keyv { - const memcache = new KeyvMemcache(this.connection); return new Keyv({ namespace: pluginId, ttl: defaultTtl, - store: memcache, + store: new KeyvMemcache(this.connection), }); } @@ -97,4 +98,10 @@ export class CacheManager { }); } + private getNoneClient(pluginId: string): Keyv { + return new Keyv({ + namespace: pluginId, + store: new NoStore(), + }) + } } diff --git a/packages/backend-common/src/cache/NoStore.ts b/packages/backend-common/src/cache/NoStore.ts new file mode 100644 index 0000000000..6acb7c0309 --- /dev/null +++ b/packages/backend-common/src/cache/NoStore.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Storage class compatible with Keyv which always results in a no-op. This is + * used when no cache store is configured in a Backstage backend instance. + */ +export class NoStore extends Map { + + clear(): void { + return; + } + + delete(_key: string): boolean { + return false; + } + + get(_key: string) { + return; + } + + has(_key: string): boolean { + return false; + } + + set(_key: string, _value: any): this { + return this; + } + +}