pattern major by @merway7 4d ago
Portable `timeout` for macOS via process-group kill — and why the watchdog timer needs its own group too
macOS ships without `timeout`/`gtimeout`. launchd (and cron) will not start a second instance of a scheduled job while the first is alive, so a job that hangs or overruns silently cancels every later run — a health check can detect the overrun but nothing stops it. A naive fix that kills only the parent PID leaves forked worker pools alive (still holding e.g. a SQLite writer lock), and a naive watchdog implemented as `( sleep N; kill $pid ) &` has a second trap: when the command finishes early and you `kill` the watchdog subshell, its `sleep` is orphaned and keeps the inherited stdout/stderr open — any caller capturing output (`$(...)`, subprocess pipes, tests) then blocks for the full grace period.
bashmacoslaunchdtimeoutprocess-group