Merge pull request #177 from nut-tree/fix/174/waitFor-does-not-properly-cancel

(#174) Cancel interval timer creation
This commit is contained in:
Sven Hettwer
2020-11-10 12:59:52 +01:00
committed by GitHub
2 changed files with 59 additions and 31 deletions
+24
View File
@@ -118,4 +118,28 @@ describe("poll-action", () => {
expect(action).toBeCalledTimes(1);
expect((end - start)).toBeLessThan(updateInterval);
});
it("should fail if action does not resolve within timeout", async () => {
// GIVEN
const updateInterval = 100;
const maxDuration = 200;
const action = jest.fn(() => {
return new Promise((_, reject) => {
setTimeout(() => reject(), 300);
})
});
// WHEN
const start = Date.now();
try {
await timeout(updateInterval, maxDuration, action);
} catch (e) {
expect(e).toEqual(`Action timed out after ${maxDuration} ms`);
}
const end = Date.now();
// THEN
expect(action).toBeCalledTimes(1);
expect((end - start)).toBeGreaterThanOrEqual(maxDuration);
});
});
+35 -31
View File
@@ -1,41 +1,45 @@
export function timeout<R>(updateIntervalMs: number, maxDurationMs: number, action: (...params: any) => Promise<R>): Promise<R> {
return new Promise<R>((resolve, reject) => {
let interval: NodeJS.Timeout;
const maxTimeout = setTimeout(
() => {
clearTimeout(maxTimeout);
if (interval) {
clearTimeout(interval);
}
reject(`Action timed out after ${maxDurationMs} ms`);
},
maxDurationMs
);
const startInterval = () => {
interval = setTimeout(function intervalFunc() {
action().then((result) => {
if (!result) {
interval = setTimeout(intervalFunc, updateIntervalMs);
} else {
clearTimeout(maxTimeout);
clearTimeout(interval);
resolve(result);
}
}).catch(() => {
interval = setTimeout(intervalFunc, updateIntervalMs);
});
}, updateIntervalMs);
};
let timerCleaned = false
action().then((result) => {
function executeInterval() {
action().then(validateResult).catch(handleRejection);
}
function validateResult(result: R){
if (!result) {
startInterval();
interval = setTimeout(executeInterval, updateIntervalMs);
} else {
clearTimeout(maxTimeout);
cleanupTimer();
resolve(result);
}
}).catch(() => {
startInterval();
});
}
function handleRejection() {
if(!timerCleaned){
interval = setTimeout(executeInterval, updateIntervalMs);
}
}
function cleanupTimer(){
timerCleaned = true
if(maxTimeout){
clearTimeout(maxTimeout);
}
if(interval){
clearTimeout(interval);
}
}
const maxTimeout = setTimeout(
() => {
cleanupTimer();
reject(`Action timed out after ${maxDurationMs} ms`);
},
maxDurationMs
);
executeInterval()
});
}