Skip to content

Fix Nanny race conditions when worker fails to start (flaky test_failure_during_worker_initialization)#9313

Merged
crusaderky merged 11 commits into
dask:mainfrom
crusaderky:test_failure_during_worker_initialization
Jul 2, 2026
Merged

Fix Nanny race conditions when worker fails to start (flaky test_failure_during_worker_initialization)#9313
crusaderky merged 11 commits into
dask:mainfrom
crusaderky:test_failure_during_worker_initialization

Conversation

@crusaderky

@crusaderky crusaderky commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Fix race conditions triggered when the worker fails to start (eg. in the test, due to a bad kwarg) and:

  • the nanny would sometimes restart it, whereas a failure to start at all should never be retried; or
  • the nanny would occasionally hang.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Unit Test Results

See test report for an extended history of previous test failures. This is useful for diagnosing flaky tests.

    40 files  ±    0      40 suites  ±0   14h 54m 18s ⏱️ + 38m 53s
 4 153 tests  -     2   3 973 ✅ +    3    178 💤  -  2  1 ❌  - 4  1 🔥 +1 
80 818 runs  +1 398  76 578 ✅ +1 366  4 237 💤 +34  2 ❌  - 3  1 🔥 +1 

For more details on these failures and errors, see this check.

Results for commit a571c4a. ± Comparison against base commit 2d43f7f.

This pull request removes 2 tests.
distributed.cli.tests.test_dask_worker.test_listen_address_ipv6[tcp:..[ ‑ 1]:---nanny]
distributed.cli.tests.test_dask_worker.test_listen_address_ipv6[tcp:..[ ‑ 1]:---no-nanny]

♻️ This comment has been updated with latest results.

@crusaderky crusaderky force-pushed the test_failure_during_worker_initialization branch 2 times, most recently from 016ac23 to a86d6d3 Compare July 1, 2026 21:49
crusaderky and others added 3 commits July 1, 2026 22:55
When a worker subprocess fails during initial startup (e.g. an invalid
kwarg), it reports the failure via init_result_q and then exits
gracefully. On slower machines this raced with both the process-exit
callback and the Nanny startup teardown, producing several intermittent
failures: a spurious "Restarting worker", a 30s hang, or a leaked
QueueFeederThread.

Three coordinated fixes in nanny.py:

- Nanny._on_worker_exit: add Status.init to the restart skip-set, so a
  worker process exit during initial startup is not mistaken for a
  transient post-startup crash and does not trigger a restart. (This
  matches the skip-set already used just above for unregistering.)

- WorkerProcess.start: only transition starting -> failed. A concurrent
  mark_stopped() (fired by the process-exit callback) may already have
  moved the state to stopped and released resources; clobbering it with
  failed left a failed-but-released state that made kill() raise midway
  through Nanny.close(), leaving the Nanny in Status.closing so the next
  close() hung on finished() until the test timed out.

- WorkerProcess.start: drop the eager terminate() on startup failure. The
  subprocess is already shutting down after reporting the failure; a
  SIGTERM races that shutdown and, if it lands while the subprocess holds
  a multiprocessing queue lock, deadlocks the parent-side queue feeder
  thread. Any lingering process is still reaped gracefully by the
  following Nanny.close() -> WorkerProcess.kill().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@crusaderky crusaderky force-pushed the test_failure_during_worker_initialization branch from 76454cd to 2376b46 Compare July 1, 2026 21:55
crusaderky and others added 8 commits July 2, 2026 12:15
The subprocess reports its startup failure via init_result_q and then
exits on its own. While WorkerProcess.start()'s exception handler awaits
terminate(), the process-exit callback can fire mark_stopped(), which
sets Status.stopped and releases init_result_q, child_stop_q and process.

Unconditionally overwriting that with Status.failed made the following
Nanny.close() -> WorkerProcess.kill() skip its Status.stopped early exit
and crash with an AttributeError on the released child_stop_q, aborting
Nanny.close() midway with the Nanny stuck in Status.closing. The second
close() call from Server.start_unsafe's exception handler then waited on
finished() forever, hanging the test until its 30s timeout.

Guard the terminate() call (the process may already be released) and only
transition starting -> failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@crusaderky crusaderky changed the title WIP fix flaky test_failure_during_worker_initialization Fix Nanny race conditions when worker fails to start (flaky test_failure_during_worker_initialization) Jul 2, 2026
@crusaderky crusaderky added bug Something is broken flaky test Intermittent failures on CI. stability Issue or feature related to cluster stability (e.g. deadlock) p2 Affects more than a few users but doesn't prevent core functions deadlock The cluster appears to not make any progress labels Jul 2, 2026
@crusaderky crusaderky marked this pull request as ready for review July 2, 2026 14:13
@crusaderky crusaderky requested a review from fjetter as a code owner July 2, 2026 14:13
@crusaderky crusaderky added the tests Unit tests and/or continuous integration label Jul 2, 2026
@crusaderky crusaderky merged commit ace5560 into dask:main Jul 2, 2026
46 of 51 checks passed
@crusaderky crusaderky deleted the test_failure_during_worker_initialization branch July 2, 2026 14:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something is broken deadlock The cluster appears to not make any progress flaky test Intermittent failures on CI. p2 Affects more than a few users but doesn't prevent core functions stability Issue or feature related to cluster stability (e.g. deadlock) tests Unit tests and/or continuous integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant