#11752: fix(heartbeat): clamp setTimeout delay to 2^31-1 to prevent TimeoutOverflowWarning
stale
Cluster:
Heartbeat Functionality Improvements
## Problem
When a cron job's `nextDue` timestamp is far in the future (e.g. `at`-type jobs scheduled months/years out), the computed `setTimeout` delay exceeds the 32-bit signed integer maximum (`2^31 - 1 = 2,147,483,647 ms ≈ 24.8 days`).
Node.js silently clamps such values to `1ms`, emitting a `TimeoutOverflowWarning`, which causes the heartbeat timer to fire immediately and re-schedule in a tight loop. This results in:
- **`gateway.err.log` growing at ~1 GB/hour** (TimeoutOverflowWarning spam)
- **CPU pegged at 50%+** due to the infinite re-scheduling loop
- **Disk exhaustion** (observed: 43 GB log file before detection)
## Root Cause
```ts
// src/infra/heartbeat-runner.ts:910
const delay = Math.max(0, nextDue - now);
// When nextDue - now > 2^31-1, Node.js treats it as 1ms → infinite loop
```
## Fix
Clamp the delay to the maximum safe `setTimeout` value:
```ts
const MAX_TIMEOUT = 2_147_483_647; // setTimeout max (2^31 - 1)
const delay = Math.min(Math.max(0, nextDue - now), MAX_TIMEOUT);
```
This ensures the timer fires at most ~24.8 days later, at which point `scheduleNext` recalculates and re-schedules correctly.
## Impact
- **Before**: Any `at`-type cron job >24.8 days in the future triggers infinite log spam
- **After**: Timer safely caps at ~24.8 days and re-evaluates on wake
## Verified
Tested on production gateway (v2026.2.6-3). After patching the compiled bundles and doing a full process restart:
- `gateway.err.log`: 662K lines → 18 lines (1.0 KB)
- CPU: 56% → 7.8%
- Zero `TimeoutOverflowWarning` emissions
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This change updates the heartbeat runner’s scheduling logic to clamp the `setTimeout` delay to Node.js’ maximum supported timeout (`2^31 - 1` ms). It prevents `TimeoutOverflowWarning` and the resulting tight reschedule loop when the next due timestamp is far in the future, while preserving the existing behavior of recomputing the next due time on wake.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- The change is localized to one scheduling calculation, matches Node.js timeout constraints, and does not alter control flow beyond preventing overflow-induced immediate timers. No other code paths depend on the unclamped larger delay value.
- src/infra/heartbeat-runner.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#9184: Fix: Heartbeat timer not resuming after macOS sleep/wake cycle
by vishaltandale00 · 2026-02-05
82.1%
#10918: fix(cron): add tolerance for timer precision and skip due jobs in r...
by Cherwayway · 2026-02-07
79.8%
#8034: fix(cron): run past-due one-shot jobs immediately on startup
by FelixFoster · 2026-02-03
79.7%
#10636: fix: setTimeout integer overflow causing server crash
by devmangel · 2026-02-06
79.6%
#19745: fix(heartbeat): enforce interval check regardless of trigger source
by misterdas · 2026-02-18
79.5%
#9114: Fix: Reduce NO_TIMEOUT_MS to 24 days to avoid Node.js overflow warning
by vishaltandale00 · 2026-02-04
79.4%
#8418: fix: notify user after consecutive heartbeat/cron failures
by liaosvcaf · 2026-02-04
78.9%
#12131: fix(cron): ensure timer callback fires for scheduled jobs
by divol89 · 2026-02-08
78.0%
#17801: fix(heartbeat): enforce interval guard for non-interval wake reasons
by aldoeliacim · 2026-02-16
77.9%
#11416: fix: clamp timeout values to avoid 32-bit overflow warning
by seojoonkim · 2026-02-07
77.7%