Skip to content

Commit 5a0083b

Browse files
committed
fix(core): use a monotonic clock for the drain watchdog
Addresses review feedback: Date.now() is wall-clock time, so an NTP adjustment or VM migration could fire the stall watchdog prematurely (clock jumps forward) or delay it (clock jumps backward). performance.now() is monotonic and immune to clock adjustments. The wall-clock Date.now() uses for history timestamps are untouched.
1 parent baa9995 commit 5a0083b

1 file changed

Lines changed: 8 additions & 4 deletions

File tree

packages/core/src/services/shellExecutionService.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,10 +1061,11 @@ export class ShellExecutionService {
10611061

10621062
// Updated every time an output chunk settles so the post-exit drain
10631063
// watchdog only fires when the chain is stuck, never while it is
1064-
// slow but advancing.
1065-
let lastDrainActivityAt = Date.now();
1064+
// slow but advancing. Uses the monotonic clock: wall-clock (Date.now)
1065+
// adjustments, e.g. NTP, must not fire or delay the watchdog.
1066+
let lastDrainActivityAt = performance.now();
10661067
const markDrainActivity = () => {
1067-
lastDrainActivityAt = Date.now();
1068+
lastDrainActivityAt = performance.now();
10681069
};
10691070

10701071
let isStreamingRawContent = true;
@@ -1415,7 +1416,10 @@ export class ShellExecutionService {
14151416
markDrainActivity();
14161417
const drainStalled = new Promise<'drain-stalled'>((res) => {
14171418
drainWatchdog = setInterval(() => {
1418-
if (Date.now() - lastDrainActivityAt >= DRAIN_STALL_TIMEOUT_MS) {
1419+
if (
1420+
performance.now() - lastDrainActivityAt >=
1421+
DRAIN_STALL_TIMEOUT_MS
1422+
) {
14191423
res('drain-stalled');
14201424
}
14211425
}, DRAIN_STALL_POLL_MS);

0 commit comments

Comments
 (0)