From 413c9fab08389bd619a4f1ecc9578194a030e2c2 Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Fri, 7 Jan 2022 17:47:59 -0500 Subject: [PATCH] Cancel cache read if it takes too long Signed-off-by: Joe Porpeglia --- .../src/service/CachedEntityLoader.test.ts | 15 +++++++++++++++ .../src/service/CachedEntityLoader.ts | 18 ++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/plugins/techdocs-backend/src/service/CachedEntityLoader.test.ts b/plugins/techdocs-backend/src/service/CachedEntityLoader.test.ts index aa5022d3a6..3c71a3d662 100644 --- a/plugins/techdocs-backend/src/service/CachedEntityLoader.test.ts +++ b/plugins/techdocs-backend/src/service/CachedEntityLoader.test.ts @@ -130,4 +130,19 @@ describe('CachedEntityLoader', () => { ttl: 5000, }); }); + + it('calls the catalog if the cache read takes too long', async () => { + identity.authenticate.mockResolvedValue(identityResponse); + cache.get.mockImplementation( + () => + new Promise(resolve => { + setTimeout(() => resolve(undefined), 10000); + }), + ); + catalog.getEntityByName.mockResolvedValue(entity); + + const result = await loader.load(entityName, token); + + expect(result).toEqual(entity); + }); }); diff --git a/plugins/techdocs-backend/src/service/CachedEntityLoader.ts b/plugins/techdocs-backend/src/service/CachedEntityLoader.ts index 5f871ff386..4e59ccd535 100644 --- a/plugins/techdocs-backend/src/service/CachedEntityLoader.ts +++ b/plugins/techdocs-backend/src/service/CachedEntityLoader.ts @@ -30,9 +30,10 @@ export type CachedEntityLoaderOptions = { }; export class CachedEntityLoader { - private catalog: CatalogClient; - private cache: CacheClient; - private identity: IdentityClient; + private readonly catalog: CatalogClient; + private readonly cache: CacheClient; + private readonly identity: IdentityClient; + private readonly readTimeout = 1000; constructor({ catalog, cache, identity }: CachedEntityLoaderOptions) { this.catalog = catalog; @@ -45,7 +46,7 @@ export class CachedEntityLoader { token: string | undefined, ): Promise { const cacheKey = await this.getCacheKey(entityName, token); - let result = (await this.cache.get(cacheKey)) as Entity | undefined; + let result = await this.getFromCache(cacheKey); if (result) { return result; @@ -68,6 +69,15 @@ export class CachedEntityLoader { return result; } + private async getFromCache(key: string): Promise { + // Promise.race ensures we don't hang the client for long if the cache is + // temporarily unreachable. + return (await Promise.race([ + this.cache.get(key), + new Promise(cancelAfter => setTimeout(cancelAfter, this.readTimeout)), + ])) as Entity | undefined; + } + private async getCacheKey( entityName: EntityName, token: string | undefined,