Skip to content

Force-kill hung ipdevpoll on stop/restart (fixes #4125)#4126

Open
adobloug wants to merge 2 commits into
Uninett:masterfrom
adobloug:bugfix/4125-ipdevpoll-stop-timeout
Open

Force-kill hung ipdevpoll on stop/restart (fixes #4125)#4126
adobloug wants to merge 2 commits into
Uninett:masterfrom
adobloug:bugfix/4125-ipdevpoll-stop-timeout

Conversation

@adobloug

@adobloug adobloug commented Jul 9, 2026

Copy link
Copy Markdown

Fixes #4125

Problem

nav stop/nav restart ipdevpoll frequently time out and report Failed
when ipdevpoll runs in multiprocess mode (ipdevpolld -m), especially on busy
installations. The master process outlives the stop attempt and its workers are
left behind as <defunct> (zombie) children.

Root cause

Two independent defects combine:

  1. nav stop never force-kills. DaemonService.stop() sent SIGTERM up to
    three times over ~12s and then gave up. It never escalated to SIGKILL, and
    only signalled the master pid — not the worker children.
  2. ipdevpoll's SIGTERM handling is cooperative and unbounded. The handler
    only schedules reactor.stop(), which needs the main thread to reach the
    reactor loop. During shutdown the main thread blocks in the thread pool join
    (no timeout), or is starved of the GIL by a busy C-extension thread — so the
    handler cannot run and SIGTERM appears ignored (observed: master at 99% CPU,
    eight <defunct> workers).

Verified on NAV 5.19.1 — this is a shutdown/kill-handling bug, not a
DB-driver bug.

Fix

  • nav.startstop: send SIGTERM to the whole process group, poll for exit on
    a monotonic clock during a grace period, then escalate to SIGKILL (uncatchable)
    and signal the group again to sweep orphan/zombie children.
  • ipdevpoll: arm a watchdog on shutdown that calls os._exit() if the reactor
    has not shut down within a configurable shutdown_timeout (default 30s),
    guaranteeing the process dies even when the reactor is wedged. Cancelled on a
    clean shutdown.

Both fixes are workload- and driver-agnostic.

Tests

  • tests/unittests/startstop_test.py: SIGTERM→SIGKILL escalation ordering,
    process-group signalling, single-process fallback, already-gone handling.
  • tests/unittests/ipdevpoll/daemon_test.py: watchdog arm (once), cancel on
    clean shutdown, and forced os._exit when it fires.

🤖 Generated with Claude Code

adobloug and others added 2 commits July 9, 2026 10:21
DaemonService.stop() sent SIGTERM up to three times over a ~12 second
window and then gave up, reporting failure. It never escalated to
SIGKILL and only ever signalled the master pid. A daemon whose main
thread is blocked or GIL-starved during shutdown can neither run its
SIGTERM handler nor exit within that window, so "nav stop"/"nav restart"
would time out and leave the process (and, for ipdevpoll -m, its worker
children) behind.

Send SIGTERM to the whole process group, poll for exit on a monotonic
clock during a grace period, then escalate to SIGKILL -- which cannot be
caught, blocked or deferred -- signalling the group again so orphaned or
zombie child processes are cleaned up along with the master.

Refs Uninett#4125

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ipdevpoll's SIGTERM handler is cooperative: it only schedules
reactor.stop(), which relies on the main thread reaching the reactor
loop to run the shutdown triggers. Under load -- especially in
multiprocess mode -- the main thread can block in the thread pool join,
or be starved of the GIL by a busy C-extension thread, so shutdown
never completes and the process appears to ignore SIGTERM entirely,
spinning at high CPU while its workers are left as <defunct> children.

Arm a watchdog timer when a shutdown signal is received. If the reactor
has not shut down cleanly within the configurable "shutdown_timeout"
(default 30s), the watchdog calls os._exit(), bypassing the reactor and
interpreter teardown to guarantee the process dies. The timer is
cancelled on a clean shutdown.

Fixes Uninett#4125

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adobloug
adobloug force-pushed the bugfix/4125-ipdevpoll-stop-timeout branch from bfd07f7 to c2f7aa7 Compare July 9, 2026 08:37
@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] nav stop/restart ipdevpoll -m times out and leaves defunct workers

2 participants