From f077d300bf49f812c78a8abc9871f64822b9ae83 Mon Sep 17 00:00:00 2001 From: Gautam Kachru Date: Wed, 2 Oct 2024 02:52:58 +0530 Subject: [PATCH] Fix: Issue of synchronizing namespaced local memory caches (#37) --- .../bentocache/src/cache/stack/cache_stack.ts | 25 +++++---- packages/bentocache/tests/bus/bus.spec.ts | 56 +++++++++++++++++++ 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/packages/bentocache/src/cache/stack/cache_stack.ts b/packages/bentocache/src/cache/stack/cache_stack.ts index dd16dc9..c190b31 100644 --- a/packages/bentocache/src/cache/stack/cache_stack.ts +++ b/packages/bentocache/src/cache/stack/cache_stack.ts @@ -20,6 +20,8 @@ export class CacheStack { l1?: LocalCache l2?: RemoteCache bus?: Bus + #busDriver?: BusDriver + #busOptions?: BusOptions defaultOptions: CacheEntryOptions logger: Logger @@ -46,22 +48,23 @@ export class CacheStack { if (bus) return bus if (!busDriver || !this.l1) return - const opts = lodash.merge({ retryQueue: { enabled: true, maxSize: undefined } }, busOptions) - const newBus = new Bus(busDriver, this.l1, this.logger, this.emitter, opts) + this.#busDriver = busDriver + this.#busOptions = lodash.merge( + { retryQueue: { enabled: true, maxSize: undefined } }, + busOptions, + ) + const newBus = new Bus(this.#busDriver, this.l1, this.logger, this.emitter, this.#busOptions) return newBus } namespace(namespace: string) { - return new CacheStack( - this.name, - this.options, - { - l1Driver: this.l1?.namespace(namespace), - l2Driver: this.l2?.namespace(namespace), - }, - this.bus, - ) + return new CacheStack(this.name, this.options, { + l1Driver: this.l1?.namespace(namespace), + l2Driver: this.l2?.namespace(namespace), + busDriver: this.#busDriver, + busOptions: this.#busOptions, + }) } emit(event: CacheEvent) { diff --git a/packages/bentocache/tests/bus/bus.spec.ts b/packages/bentocache/tests/bus/bus.spec.ts index c12c089..0d9df72 100644 --- a/packages/bentocache/tests/bus/bus.spec.ts +++ b/packages/bentocache/tests/bus/bus.spec.ts @@ -33,6 +33,62 @@ test.group('Bus synchronization', () => { assert.isUndefined(await cache3.get(key)) }).disableTimeout() + test('synchronize multiple cache with a namespace', async ({ assert }) => { + const key = 'foo' + + const [cache1] = new CacheFactory().withL1L2Config().create() + const [cache2] = new CacheFactory().withL1L2Config().create() + const [cache3] = new CacheFactory().withL1L2Config().create() + + await cache1.namespace('users').set(key, 24) + await setTimeout(100) + + assert.equal(await cache1.namespace('users').get(key), 24) + assert.equal(await cache2.namespace('users').get(key), 24) + assert.equal(await cache3.namespace('users').get(key), 24) + + await cache1.namespace('users').delete(key) + + await setTimeout(100) + + assert.isUndefined(await cache1.namespace('users').get(key)) + assert.isUndefined(await cache2.namespace('users').get(key)) + assert.isUndefined(await cache3.namespace('users').get(key)) + }).disableTimeout() + + test('synchronize multiple cache with multiple namespaces', async ({ assert }) => { + const key = 'bar' + + const [cache1] = new CacheFactory().withL1L2Config().create() + const [cache2] = new CacheFactory().withL1L2Config().create() + const [cache3] = new CacheFactory().withL1L2Config().create() + + const cache1NSUsersMe = cache1.namespace('users').namespace('me') + const cache2NSUsersMe = cache2.namespace('users').namespace('me') + const cache3NSAdmin = cache3.namespace('admin') + + await cache1NSUsersMe.set(key, 24) + await cache3NSAdmin.set(key, 42) + await setTimeout(100) + + assert.equal(await cache1NSUsersMe.get(key), 24) + assert.equal(await cache2NSUsersMe.get(key), 24) + assert.equal(await cache3NSAdmin.get(key), 42) + + await cache1NSUsersMe.clear() + + await setTimeout(100) + + assert.isUndefined(await cache1NSUsersMe.get(key)) + assert.isUndefined(await cache2.namespace('users').namespace('me').get(key)) + assert.equal(await cache3NSAdmin.get(key), 42) + + await cache2.namespace('admin').clear() + await setTimeout(100) + + assert.isUndefined(await cache3NSAdmin.get(key)) + }).disableTimeout() + test('retry queue processing', async ({ assert }) => { const bus1 = new ChaosBus(new MemoryTransport()) const bus2 = new ChaosBus(new MemoryTransport())