mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-08 08:45:41 +00:00
* fix(heartbeat): clamp scheduler delay to Node setTimeout cap (#71414)
When `agents.defaults.heartbeat.every` resolves to >2_147_483_647 ms
(~24.85d), the previous scheduleNext() called setTimeout with the raw
delay. Node clamps any delay > 2^31-1 to 1 ms, fires the callback, and
the heartbeat re-arms with the same oversized value - a tight loop that
floods the log with TimeoutOverflowWarning and crashes the gateway with
exit code 1.
Clamp the computed delay to HEARTBEAT_MAX_TIMEOUT_MS (2_147_483_647)
before calling setTimeout. The worst case is now one heartbeat every
~24.85d instead of crash-loop. Warn once per process when clamping
fires, so a misconfigured "365d" remains visible without flooding.
This is a defense-in-depth fix at the scheduler layer; loadConfig-level
rejection is a broader change with more blast radius and a separate
question (some users may legitimately want "every: 365d" to mean
"effectively never"). The clamped behaviour is closer to that intent
than the crash is.
Test: new scheduler test sets heartbeat.every="365d" with fake timers,
advances 60s, and asserts runSpy was never called (with the bug, it
would be called ~60_000 times).
* style: format heartbeat scheduler clamp
* fix: share safe timeout delay clamp (#71478) (thanks @hclsys)
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
(cherry picked from commit fd74fc5a4f)
20 lines
679 B
TypeScript
20 lines
679 B
TypeScript
export const MAX_SAFE_TIMEOUT_DELAY_MS = 2_147_483_647;
|
|
|
|
export function resolveSafeTimeoutDelayMs(delayMs: number, opts?: { minMs?: number }): number {
|
|
const rawMinMs = opts?.minMs ?? 1;
|
|
const minMs = Math.min(
|
|
MAX_SAFE_TIMEOUT_DELAY_MS,
|
|
Math.max(0, Number.isFinite(rawMinMs) ? Math.floor(rawMinMs) : 1),
|
|
);
|
|
const candidateMs = Number.isFinite(delayMs) ? Math.floor(delayMs) : minMs;
|
|
return Math.min(MAX_SAFE_TIMEOUT_DELAY_MS, Math.max(minMs, candidateMs));
|
|
}
|
|
|
|
export function setSafeTimeout(
|
|
callback: () => void,
|
|
delayMs: number,
|
|
opts?: { minMs?: number },
|
|
): NodeJS.Timeout {
|
|
return setTimeout(callback, resolveSafeTimeoutDelayMs(delayMs, opts));
|
|
}
|