From c1e89e967068631a5d0c60d826ed43580247629d Mon Sep 17 00:00:00 2001 From: Maciej Pyrc Date: Mon, 9 Dec 2024 14:15:47 +0100 Subject: [PATCH] feat: cache tests --- .yarn/releases/yarn-1.19.0.cjs | 2 +- .../cache/cache.garbage-collector.spec.ts | 29 +++++++-------- .../features/cache/cache.lazy-storage.spec.ts | 2 +- packages/core/src/cache/cache.ts | 37 +++++++++++++++---- packages/core/src/dispatcher/dispatcher.ts | 2 +- packages/core/src/managers/app/app.manager.ts | 2 +- .../src/managers/logger/logger.manager.ts | 2 +- .../src/managers/request/request.manager.ts | 2 +- packages/sockets/src/socket/socket.ts | 2 +- 9 files changed, 49 insertions(+), 31 deletions(-) diff --git a/.yarn/releases/yarn-1.19.0.cjs b/.yarn/releases/yarn-1.19.0.cjs index 51ccdedbe..e038c0065 100755 --- a/.yarn/releases/yarn-1.19.0.cjs +++ b/.yarn/releases/yarn-1.19.0.cjs @@ -102029,7 +102029,7 @@ wercker.yml // I know what you're about to say. But literally everything about // signal-exit is a compromise with evil. Get used to it. if (!emitter.infinite) { - emitter.setMaxListeners(20000); + emitter.setMaxListeners(1000); emitter.infinite = true; } diff --git a/packages/core/__tests__/features/cache/cache.garbage-collector.spec.ts b/packages/core/__tests__/features/cache/cache.garbage-collector.spec.ts index fcfaac16e..4d3a02552 100644 --- a/packages/core/__tests__/features/cache/cache.garbage-collector.spec.ts +++ b/packages/core/__tests__/features/cache/cache.garbage-collector.spec.ts @@ -69,33 +69,30 @@ describe("Cache [ Garbage Collector ]", () => { }); it("should schedule garbage collection on mount", async () => { const storage = new Map(); - storage.set(cacheKey, cacheData); - const cacheInstance = createCache(client, { + storage.set("cacheKey", cacheData); + + const cacheInstance = createCache(new Client({ url: "shared-base-url" }), { storage, version, }); + expect(Array.from(cacheInstance.garbageCollectors.keys())).toHaveLength(1); + }); + it("should schedule lazy storage garbage collection on mount", async () => { + lazyStorage.set(cacheKey, cacheData); + const cacheInstance = createCache(client, { + lazyStorage: createLazyCacheAdapter(lazyStorage), + version, + }); + await waitFor(() => { expect(Array.from(cacheInstance.garbageCollectors.keys())).toHaveLength(1); }); }); - // it("should schedule lazy storage garbage collection on mount", async () => { - // lazyStorage.set(cacheKey, cacheData); - // const cacheInstance = createCache(client, { - // lazyStorage: createLazyCacheAdapter(lazyStorage), - // version, - // }); - - // await waitFor(() => { - // expect(Array.from(cacheInstance.garbageCollectors.keys())).toHaveLength(1); - // }); - // }); it("should schedule garbage collection when resource is added", async () => { const spy = jest.spyOn(cache, "scheduleGarbageCollector"); cache.set(request, cacheData); - await waitFor(() => { - expect(spy).toHaveBeenCalledTimes(1); - }); + expect(spy).toHaveBeenCalledTimes(1); }); it("should remove resource with not matching lazy version", async () => { const data = { ...cacheData, cacheTime: Time.MIN }; diff --git a/packages/core/__tests__/features/cache/cache.lazy-storage.spec.ts b/packages/core/__tests__/features/cache/cache.lazy-storage.spec.ts index afbd4002c..c6f745103 100644 --- a/packages/core/__tests__/features/cache/cache.lazy-storage.spec.ts +++ b/packages/core/__tests__/features/cache/cache.lazy-storage.spec.ts @@ -97,7 +97,7 @@ describe("Cache [ Lazy Storage ]", () => { const otherKey = "otherKey"; await cache.options?.lazyStorage?.set(cacheKey, cacheData); await cache.storage.set(otherKey, cacheData); - const keys = await cache.getLazyKeys(); + const keys = await cache.getAllKeys(); await sleep(50); expect(keys).toStrictEqual([cacheKey, otherKey]); }); diff --git a/packages/core/src/cache/cache.ts b/packages/core/src/cache/cache.ts index 37028ec5a..c69bc07cd 100644 --- a/packages/core/src/cache/cache.ts +++ b/packages/core/src/cache/cache.ts @@ -36,8 +36,10 @@ export class Cache { public client: C, public options?: CacheOptionsType, ) { - this.emitter?.setMaxListeners(20000); - this.storage = this.options?.storage || (new Map() as typeof this.storage); + const { storage = new Map() } = this.options || {}; + + this.storage = storage; + this.emitter?.setMaxListeners(1000); this.events = getCacheEvents(this.emitter); this.options?.onInitialization?.(this); @@ -45,12 +47,20 @@ export class Cache { this.lazyStorage = this.options?.lazyStorage; this.logger = this.client.loggerManager.init("Cache"); - [...this.storage.keys()].forEach(this.scheduleGarbageCollector); + const scheduleGarbageCollector = (keys: string[]) => { + keys.forEach(this.scheduleGarbageCollector); - // Going back from offline should re-trigger garbage collection - this.client.appManager.events.onOnline(() => { - [...this.storage.keys()].forEach(this.scheduleGarbageCollector); - }); + // Going back from offline should re-trigger garbage collection + this.client.appManager.events.onOnline(() => { + keys.forEach(this.scheduleGarbageCollector); + }); + }; + + scheduleGarbageCollector([...this.storage.keys()]); + + // Schedule garbage collection for lazy storage + // To make sure we do not store some data that is no longer needed + this.getLazyKeys().then(scheduleGarbageCollector); } /** @@ -178,7 +188,7 @@ export class Cache { */ invalidate = async (invalidateKeys: string | RegExp | RequestInstance | Array) => { this.logger.debug("Revalidating cache element", { invalidateKeys }); - const keys = await this.getLazyKeys(); + const keys = await this.getAllKeys(); const invalidate = (key: string | RegExp | RequestInstance) => { const handleInvalidation = (cacheKey: string) => { @@ -249,6 +259,16 @@ export class Cache { * @param cacheKey */ getLazyKeys = async () => { + const keys = (await this.lazyStorage?.keys()) || []; + + return [...new Set(keys)]; + }; + + /** + * Used to receive keys from sync storage and lazy storage + * @param cacheKey + */ + getAllKeys = async () => { const keys = await this.lazyStorage?.keys(); const asyncKeys = Array.from(keys || []); const syncKeys = Array.from(this.storage.keys()); @@ -294,6 +314,7 @@ export class Cache { * Clear cache storages */ clear = async (): Promise => { + this.garbageCollectors.forEach((timeout) => clearTimeout(timeout)); this.storage.clear(); }; } diff --git a/packages/core/src/dispatcher/dispatcher.ts b/packages/core/src/dispatcher/dispatcher.ts index f4d1fadae..bde84d245 100644 --- a/packages/core/src/dispatcher/dispatcher.ts +++ b/packages/core/src/dispatcher/dispatcher.ts @@ -34,7 +34,7 @@ export class Dispatcher { public client: ClientInstance, public options?: DispatcherOptionsType, ) { - this.emitter?.setMaxListeners(20000); + this.emitter?.setMaxListeners(1000); this.logger = client.loggerManager.init("Dispatcher"); if (this.options?.storage) { diff --git a/packages/core/src/managers/app/app.manager.ts b/packages/core/src/managers/app/app.manager.ts index dddf88200..c43dbec2a 100644 --- a/packages/core/src/managers/app/app.manager.ts +++ b/packages/core/src/managers/app/app.manager.ts @@ -19,7 +19,7 @@ export class AppManager { isFocused: boolean; constructor(public options?: AppManagerOptionsType) { - this.emitter?.setMaxListeners(20000); + this.emitter?.setMaxListeners(1000); const { focusEvent = appManagerInitialOptions.focusEvent, onlineEvent = appManagerInitialOptions.onlineEvent, diff --git a/packages/core/src/managers/logger/logger.manager.ts b/packages/core/src/managers/logger/logger.manager.ts index b644a70fc..518f50194 100644 --- a/packages/core/src/managers/logger/logger.manager.ts +++ b/packages/core/src/managers/logger/logger.manager.ts @@ -18,7 +18,7 @@ export class LoggerManager { private client: Pick, private options?: LoggerOptionsType, ) { - this.emitter?.setMaxListeners(20000); + this.emitter?.setMaxListeners(1000); this.logger = this.options?.logger || logger; this.severity = this.options?.severity || 2; } diff --git a/packages/core/src/managers/request/request.manager.ts b/packages/core/src/managers/request/request.manager.ts index 8c5331480..175bdc11a 100644 --- a/packages/core/src/managers/request/request.manager.ts +++ b/packages/core/src/managers/request/request.manager.ts @@ -10,7 +10,7 @@ export class RequestManager { events = getRequestManagerEvents(this.emitter); constructor() { - this.emitter?.setMaxListeners(20000); + this.emitter?.setMaxListeners(1000); } abortControllers = new Map>(); diff --git a/packages/sockets/src/socket/socket.ts b/packages/sockets/src/socket/socket.ts index 80fec3d75..124729146 100644 --- a/packages/sockets/src/socket/socket.ts +++ b/packages/sockets/src/socket/socket.ts @@ -59,7 +59,7 @@ export class Socket) { const { url, adapter, queryParams, reconnect, reconnectTime, queryParamsConfig, queryParamsStringify } = this.options; - this.emitter?.setMaxListeners(20000); + this.emitter?.setMaxListeners(1000); this.url = url; this.queryParams = queryParams; this.debug = false;