From 2bc3c60dfd329ccb22113e1a452453310953cfbd Mon Sep 17 00:00:00 2001 From: Simon Hofmann Date: Sat, 3 Feb 2024 23:40:30 +0100 Subject: [PATCH] Feature/556/better timeout error messages (#557) * (#556) Store intermediate results and errors to provide additional context on timeout * (#556) Update testcases --- lib/util/timeout.function.spec.ts | 22 ++++++++++++++++------ lib/util/timeout.function.ts | 22 +++++++++++++++++++--- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/lib/util/timeout.function.spec.ts b/lib/util/timeout.function.spec.ts index 2f75a674..7fc5af96 100644 --- a/lib/util/timeout.function.spec.ts +++ b/lib/util/timeout.function.spec.ts @@ -16,7 +16,9 @@ describe("timeout", () => { try { await timeout(updateInterval, maxDuration, action); } catch (e) { - expect(e).toBe(`Action timed out after ${maxDuration} ms`); + expect(e).toBe( + `Action timed out after ${maxDuration} ms. Last rejection reason was: false.`, + ); } const end = Date.now(); @@ -37,7 +39,9 @@ describe("timeout", () => { try { await timeout(updateInterval, maxDuration, action); } catch (e) { - expect(e).toEqual(`Action timed out after ${maxDuration} ms`); + expect(e).toEqual( + `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`, + ); } const end = Date.now(); @@ -90,7 +94,7 @@ describe("timeout", () => { const action = jest.fn(() => { const interval = Date.now() - start; return new Promise((resolve, reject) => - interval > delay ? resolve(true) : reject() + interval > delay ? resolve(true) : reject(), ); }); @@ -114,7 +118,9 @@ describe("timeout", () => { try { await timeout(updateInterval, maxDuration, action); } catch (e) { - expect(e).toEqual(`Action timed out after ${maxDuration} ms`); + expect(e).toEqual( + `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`, + ); } const end = Date.now(); @@ -137,7 +143,9 @@ describe("timeout", () => { const SUT = () => timeout(updateInterval, maxDuration, action); // THEN - await expect(SUT).rejects.toBe(`Action timed out after ${maxDuration} ms`); + await expect(SUT).rejects.toBe( + `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`, + ); expect(action).toBeCalledTimes(1); }); @@ -157,7 +165,9 @@ describe("timeout", () => { const SUT = () => timeout(updateInterval, maxDuration, action); // THEN - await expect(SUT).rejects.toBe(`Action timed out after ${maxDuration} ms`); + await expect(SUT).rejects.toBe( + `Action timed out after ${maxDuration} ms. Didn't receive a result within timeout.`, + ); expect(action).toBeCalledTimes(1); await sleep(500); expect(action).toBeCalledTimes(1); diff --git a/lib/util/timeout.function.ts b/lib/util/timeout.function.ts index 68222fa4..84224651 100644 --- a/lib/util/timeout.function.ts +++ b/lib/util/timeout.function.ts @@ -8,11 +8,13 @@ export function timeout( updateIntervalMs: number, maxDurationMs: number, action: (...params: any) => Promise, - config?: TimoutConfig + config?: TimoutConfig, ): Promise { return new Promise((resolve, reject) => { let interval: NodeJS.Timeout; let timerCleaned = false; + let lastResult: R | null; + let lastRejectionReason: any | null; if (config?.signal) { config.signal.onabort = () => { @@ -29,12 +31,16 @@ export function timeout( if (!result && !timerCleaned) { interval = setTimeout(executeInterval, updateIntervalMs); } else { + lastResult = result; + lastRejectionReason = null; cleanupTimer(); resolve(result); } } - function handleRejection() { + function handleRejection(reason: any) { + lastRejectionReason = reason; + lastResult = null; if (!timerCleaned) { interval = setTimeout(executeInterval, updateIntervalMs); } @@ -52,7 +58,17 @@ export function timeout( const maxTimeout = setTimeout(() => { cleanupTimer(); - reject(`Action timed out after ${maxDurationMs} ms`); + let additionalInformation: string | undefined; + if (lastResult == null && lastRejectionReason != null) { + additionalInformation = `Last rejection reason was: ${lastRejectionReason}.`; + } else if (lastResult == null && lastRejectionReason == null) { + additionalInformation = `Didn't receive a result within timeout.`; + } + reject( + `Action timed out after ${maxDurationMs} ms.${ + additionalInformation ? ` ${additionalInformation}` : "" + }`, + ); }, maxDurationMs); executeInterval();