setBigTimeout

JavaScript’s built‑in `setTimeout` quietly overflows after about 25 days because many engines store delays as 32‑bit signed integers, causing extremely large timeouts to fire immediately instead of after the intended wait. A small library, `setBigTimeout`, works around this by chaining shorter timers, prompting debate over better patterns for long‑running jobs, the importance of validating user‑controlled timeouts, and the inherent imprecision and security footguns in JS timing APIs. Commenters largely argue that very long waits should be handled by schedulers or persisted jobs rather than single in‑memory timers, especially in servers, tests, and security‑sensitive rate limiting.

Use cases for very long timeouts

  • Some have hit the 32‑bit limit in real code, e.g.:
    • Client-side auth refresh scheduled near token expiry, with tabs open for 30+ days.
    • Cron-like schedulers in JS that rebuild timers from a database on startup; long jobs should not “fire immediately” just because they exceed an internal limit.
    • Cloud/task queues with a 30‑day max delay, where people already chain tasks to simulate longer delays.
  • Others argue that long timeouts are a code smell; you should track jobs in persistent storage and use a scheduler / poller instead.

JavaScript timer limits and quirks

  • setTimeout delays are effectively bounded by a 32‑bit signed integer (~25 days) in most runtimes, even though JS numbers are 64‑bit floats.
  • Very large values, Infinity, or NaN can cause callbacks to run immediately or be clamped to tiny durations; Node prints a warning and sets duration to 1ms.
  • Behavior for out-of-range or invalid delays is seen as surprising; several argue it should throw, but backward compatibility likely prevents changes.
  • JS numbers provide 53 bits of integer precision, but various operations (bitwise, engine internals) use 32‑bit integers.

Implementation critiques and alternatives

  • The library chains multiple 25‑day timeouts by subtracting from a remaining delay; some criticize that it:
    • Uses repeated timeouts rather than checking against a monotonic clock.
    • Tracks remaining time in floating point, which could theoretically break at astronomically large delays (though considered purely theoretical).
  • Suggestions:
    • Use a scheduler loop that regularly checks for due tasks and only schedules near-term timeouts.
    • Use monotonic timing APIs instead of Date.now() for precision.
    • Avoid requestAnimationFrame for long delays; it pauses when the tab is hidden and doesn’t work server-side.

Security, validation, and rate limiting

  • Discussion around attacker-controlled delays:
    • One view: allowing user control of raw timeouts is inherently unsafe; business logic should map user inputs to vetted, bounded values.
    • Others note this specific behavior is still a footgun: huge values can bypass naive “minimum delay” checks.
  • Better approaches suggested:
    • Proper input validation with both lower and upper bounds.
    • Token-bucket or similar rate limiting instead of naïve “one timeout per user action.”

Testing and reliability concerns

  • setTimeout has no guarantee of exact timing; it can fire earlier or later due to clock changes, scheduling, or throttling.
  • Several recommend:
    • Mocking timers and/or time in unit tests instead of waiting real seconds.
    • Designing code around virtual/simulated time for fast, deterministic tests.
  • General point: very long delays are more likely to be invalidated by process restarts than to complete; persistent schedulers are preferred.

Tooling and hosting side thread

  • Brief debate over Sourcehut’s interface:
    • Some find the “tree” terminology non-obvious or “garbage.”
    • Others defend it as standard git terminology and acceptable once you know where to click.