fix(#5): clear waitFor timer and catch poll rejections - #4
Jackallink wants to merge 1 commit into
Conversation
src/runs/postgres-run-store.ts waitFor polls getRun every 250ms with setInterval and rejects after a setTimeout. Two leaks: when finish() resolves on the first terminal status, clearInterval was called but clearTimeout was not, so the timeout still fired later and rejected an already-settled promise; and the poll itself ran as a fire-and-forget .then() with no .catch, so a DB blip became an unhandled rejection. Call clearTimeout in finish() alongside clearInterval so the timeout can never race the resolved promise. Attach .catch(() => undefined) to the poll branch to swallow transient errors and let the next tick recover. Refs: Jackallink/qm-integration#5
|
Independent review — 2026-09-04 Findings on PR #41. Timer reject path leaks events listener (separate bug, same file)The diff correctly adds But the const timer = setTimeout(() => {
if (done) return;
done = true;
clearInterval(poll);
// ❌ missing events.off(runId, onSettle)
reject(new Error(`run ${runId} did not finish within ${timeoutMs}ms`));
}, timeoutMs);If the timer fires first (timeout), Note that Out of scope for #4 (which was scoped to the poll branch and the finish/timer race). Recommend filing a follow-up issue; the fix is one line. 2.
|
|
Correction to my earlier review finding — 2026-09-04 My previous review comment claimed F4.1: "timer reject path misses events.off(runId, onSettle)". That is wrong — retracted. Verified against both const timer = setTimeout(() => {
if (done) return;
done = true;
clearInterval(poll);
events.off(runId, onSettle); // present in base
reject(new Error(...));
}, timeoutMs);The PR does not touch the timer path. No listener leak there. Apologies for the noise — the diff's addition of clearTimeout(timer) in finish() only closes the timer-vs-poll race on the success path, which is correct and sufficient. Remaining valid finding on this PR: F4.2 (PG-gated test does not cover the .catch path — suggest a mock-based unit test). |
|
Deep-review pass addendum — 2026-09-04 Verified on branch
|
Closes: Jackallink/qm-integration#5
src/runs/postgres-run-store.tswaitForpolls getRun every 250ms with setInterval and rejects after a setTimeout. Two leaks: when finish() resolves on the first terminal status, clearInterval was called but clearTimeout was not, so the timeout still fired later and rejected an already-settled promise; and the poll itself ran as a fire-and-forget .then() with no .catch, so a DB blip became an unhandled rejection.Call clearTimeout in finish() alongside clearInterval so the timeout can never race the resolved promise. Attach .catch(() => undefined) to the poll branch to swallow transient errors and let the next tick recover.
Affected tests
Reviewer checklist