From 161459d9c6d5b0283a61a3e89664dcc22263be3b Mon Sep 17 00:00:00 2001 From: Valentin Vetter Date: Tue, 31 Dec 2024 15:20:34 +0100 Subject: [PATCH] fix: don't cache rejected promises (#1238) Co-authored-by: Valentin Vetter --- .../forestadmin-client/src/utils/ttl-cache.ts | 9 +++++++-- .../test/utils/ttl-cache.test.ts | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/forestadmin-client/src/utils/ttl-cache.ts b/packages/forestadmin-client/src/utils/ttl-cache.ts index 9bb7278209..523059def8 100644 --- a/packages/forestadmin-client/src/utils/ttl-cache.ts +++ b/packages/forestadmin-client/src/utils/ttl-cache.ts @@ -5,11 +5,11 @@ export default class TTLCache { private readonly stateMap = new Map< string, - { promise: Promise | V | undefined; expirationTimestamp: number } + { promise: Promise; expirationTimestamp: number } >(); constructor( - private readonly fetchMethod: (key: string) => Promise | V | undefined, + private readonly fetchMethod: (key: string) => Promise, private readonly ttl = 1000, ) {} @@ -24,6 +24,11 @@ export default class TTLCache { const fetch = this.fetchMethod(key); this.stateMap.set(key, { promise: fetch, expirationTimestamp: now + this.ttl }); + fetch.catch(() => { + // Don't cache rejected promises + this.stateMap.delete(key); + }); + return fetch; } diff --git a/packages/forestadmin-client/test/utils/ttl-cache.test.ts b/packages/forestadmin-client/test/utils/ttl-cache.test.ts index 1317d9f74f..957352c62b 100644 --- a/packages/forestadmin-client/test/utils/ttl-cache.test.ts +++ b/packages/forestadmin-client/test/utils/ttl-cache.test.ts @@ -60,6 +60,22 @@ describe('TTL Cache', () => { expect(fetchMethod).toHaveBeenCalledTimes(2); }); + + it('should not cache a rejected promise', async () => { + const fetchMethod = jest + .fn() + .mockRejectedValueOnce(new Error('first')) + .mockResolvedValueOnce('second'); + + const cache = new TTLCache(fetchMethod); + + await expect(() => cache.fetch('key')).rejects.toThrow('first'); + + const fetch2 = await cache.fetch('key'); + expect(fetch2).toEqual('second'); + + expect(fetchMethod).toHaveBeenCalledTimes(2); + }); }); describe('clear', () => {