Skip to content

Today I learned

How do I restart a Node.js container when its event loop hangs?

A Node server stuck in an endless loop answers nothing, and Docker won't restart it: a failing healthcheck only marks it unhealthy, and restart: acts only when the process exits. Nothing on the stuck thread can notice, so the watchdog lives on a worker thread and kills the process from there.

ts
// main thread
const w = new Worker(new URL('./watchdog.js', import.meta.url), { workerData: 30_000 })
w.unref()
setInterval(() => w.postMessage(0), 1000).unref()

// watchdog.js (worker)
let last = Date.now()
parentPort.on('message', () => { last = Date.now() })
setInterval(() => {
  if (Date.now() - last > workerData) process.kill(process.pid, 'SIGKILL')
}, 1000)

The gotcha: in a container your server is PID 1, and the kernel won't deliver that SIGKILL to PID 1. Add init: true to the service in Compose so the server runs as a normal child.

I added this to a game's WebSocket gateway, where every player socket hangs on one thread. Keep it off in development: a breakpoint looks exactly like a hang. Docs: Compose init.

The 30-second version

Share LinkedIn Post on X

Related notes

Newsletter

Occasional notes on engineering, game tech, and new tools — no spam, unsubscribe anytime.

Ravy

Engineering manager, founder, and software developer building web platforms, game systems, real-time services, and automation tools. 15 years of shipped work — currently at Gaijin.net.

Get in Touch

Building an MVP, shipping a game feature, or automating a team workflow? Open source or paid — let's talk.

Contact Me
© 2020-2026 XPLOIT FZE. All trademarks, names and logos belong to their respective copyright holders.