Skip to content

[TRTLLM-13409][feat] anti-zombie worker cleanup (PR_SET_PDEATHSIG + tree-kill)#16404

Open
JunyiXu-nv wants to merge 4 commits into
NVIDIA:mainfrom
JunyiXu-nv:dev-junyix-feat-anti-zombie
Open

[TRTLLM-13409][feat] anti-zombie worker cleanup (PR_SET_PDEATHSIG + tree-kill)#16404
JunyiXu-nv wants to merge 4 commits into
NVIDIA:mainfrom
JunyiXu-nv:dev-junyix-feat-anti-zombie

Conversation

@JunyiXu-nv

@JunyiXu-nv JunyiXu-nv commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Improved cleanup of worker and descendant processes after fatal errors.
    • Reduced the risk of orphaned processes and lingering GPU memory when a parent process exits unexpectedly.
    • Added bounded waiting and resilient handling during process termination.
  • Tests

    • Added Linux coverage for parent-death handling and process-tree cleanup.
    • Included validation for repeated parent-death signal setup.

Description

When the proxy / MPI launcher dies abruptly (e.g. a watchdog hard-kill or a pod-kill), mpi4py worker processes can be left orphaned, keeping their CUDA context and holding GPU memory until the next run OOMs at model load and blames the wrong PR.

Add two anti-zombie helpers to tensorrt_llm._utils and wire them in:

  • set_parent_death_signal(): prctl(PR_SET_PDEATHSIG) so the kernel signals this process when its parent dies. Called at the top of worker_main, so every spawned executor worker self-terminates if its parent goes away. Linux-only; no-op elsewhere. Not called on the in-process LLM() path.
  • kill_process_tree(): SIGKILL a pid and all descendants (psutil-based, covers forked grandchildren), blocking until reaped. Wired into the proxy's pre_shutdown on the fatal-error path to reap the proxy's own descendant processes (postproc / local helpers).

Test Coverage

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Linux process lifecycle utilities for parent-death signaling and recursive process-tree termination, integrates them into worker startup and fatal proxy shutdown, and adds subprocess-based Linux tests registered in the A10 test list.

Changes

Anti-zombie process lifecycle

Layer / File(s) Summary
Process lifecycle utilities
tensorrt_llm/_utils.py
Adds Linux PR_SET_PDEATHSIG setup and recursive process-tree killing with bounded waits and race handling.
Executor lifecycle integration
tensorrt_llm/executor/worker.py, tensorrt_llm/executor/proxy.py
Workers configure parent-death signaling at startup; fatal proxy shutdown cleans up descendant processes while logging cleanup failures.
Linux process lifecycle validation
tests/unittest/_utils/test_anti_zombie.py, tests/integration/test_lists/test-db/l0_a10.yml
Adds Linux-only subprocess tests for parent death, process-tree reaping, repeated signal setup, and A10 test-list registration.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Worker
  participant ParentDeathSignal
  participant libc
  Worker->>ParentDeathSignal: configure default SIGKILL
  ParentDeathSignal->>libc: call prctl(PR_SET_PDEATHSIG)
  libc-->>Worker: return success or OSError
Loading
sequenceDiagram
  participant GenerationExecutorProxy
  participant kill_process_tree
  participant psutil
  participant Descendants
  GenerationExecutorProxy->>kill_process_tree: clean descendants after fatal error
  kill_process_tree->>psutil: enumerate recursive children
  kill_process_tree->>Descendants: kill processes
  kill_process_tree->>psutil: wait for process exit
Loading

Suggested reviewers: asfiyab-nvidia, yihuilu512

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise, ticketed, and clearly summarizes the anti-zombie cleanup change.
Description check ✅ Passed The description explains the issue and solution, but the Test Coverage section is empty.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
tests/unittest/_utils/test_anti_zombie.py (2)

57-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add explicit None return annotations.

All three test_* functions are non-returning and should declare -> None.

As per coding guidelines, “Annotate every function, use None for non-returning functions.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/_utils/test_anti_zombie.py` around lines 57 - 141, Add an
explicit -> None return annotation to each of the three test functions:
test_prctl_kills_child_when_parent_dies,
test_kill_process_tree_reaps_grandchildren, and
test_set_parent_death_signal_idempotent. Do not alter their behavior or
surrounding test logic.

Source: Coding guidelines


98-115: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the proxy’s include_parent=False cleanup path.

This test only exercises include_parent=True, while tensorrt_llm/executor/proxy.py Lines 629-633 relies on False. Add a case that verifies descendants exit while TOP_PID remains alive, then explicitly reap the top process. Coverage is otherwise insufficient for the integration branch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/_utils/test_anti_zombie.py` around lines 98 - 115, The test
coverage in test_kill_process_tree_reaps_grandchildren only exercises
include_parent=True; add a case using kill_process_tree with
include_parent=False that verifies CHILD_PID and GRANDCHILD_PID are reaped while
TOP_PID remains alive, then explicitly terminate and reap TOP_PID to avoid
leaking the process.

Source: Path instructions

tensorrt_llm/executor/proxy.py (1)

629-637: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Narrow the cleanup exception boundary.

except Exception also hides programming errors in the new fatal-shutdown path. Handle expected process races (psutil.Error and, if applicable, OSError) explicitly; let unrelated defects remain visible.

As per coding guidelines, “Catch the narrowest possible exceptions.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/executor/proxy.py` around lines 629 - 637, Update the cleanup
exception handler around kill_process_tree in the fatal-error shutdown path to
catch only expected process-race exceptions, specifically psutil.Error and
OSError where applicable. Preserve the existing debug logging for those
failures, while allowing unrelated programming errors to propagate.

Source: Coding guidelines

tensorrt_llm/_utils.py (1)

407-440: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Complete the public helper contracts.

Annotate sig (for example, int | None) and add Google-style Args: documentation for both exported helpers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_utils.py` around lines 407 - 440, Complete the public contracts
for set_parent_death_signal and kill_process_tree by adding an explicit type
annotation for set_parent_death_signal’s sig parameter, allowing None, and
adding Google-style Args: sections documenting each parameter in both helpers,
including defaults and behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_utils.py`:
- Around line 425-428: Update the parent-death setup helper around libc.prctl to
accept the expected parent PID, arm PR_SET_PDEATHSIG, then compare the current
getppid() with that expected PID and terminate the worker if it changed.
Preserve the existing prctl error handling, and add a regression test covering
the launcher exiting during this startup window.

In `@tests/unittest/_utils/test_anti_zombie.py`:
- Around line 57-75: Update test_prctl_kills_child_when_parent_dies to
initialize child_pid before the try block and, in finally, best-effort terminate
and reap the child when it was created but remains alive, while preserving the
existing parent cleanup.

---

Nitpick comments:
In `@tensorrt_llm/_utils.py`:
- Around line 407-440: Complete the public contracts for set_parent_death_signal
and kill_process_tree by adding an explicit type annotation for
set_parent_death_signal’s sig parameter, allowing None, and adding Google-style
Args: sections documenting each parameter in both helpers, including defaults
and behavior.

In `@tensorrt_llm/executor/proxy.py`:
- Around line 629-637: Update the cleanup exception handler around
kill_process_tree in the fatal-error shutdown path to catch only expected
process-race exceptions, specifically psutil.Error and OSError where applicable.
Preserve the existing debug logging for those failures, while allowing unrelated
programming errors to propagate.

In `@tests/unittest/_utils/test_anti_zombie.py`:
- Around line 57-141: Add an explicit -> None return annotation to each of the
three test functions: test_prctl_kills_child_when_parent_dies,
test_kill_process_tree_reaps_grandchildren, and
test_set_parent_death_signal_idempotent. Do not alter their behavior or
surrounding test logic.
- Around line 98-115: The test coverage in
test_kill_process_tree_reaps_grandchildren only exercises include_parent=True;
add a case using kill_process_tree with include_parent=False that verifies
CHILD_PID and GRANDCHILD_PID are reaped while TOP_PID remains alive, then
explicitly terminate and reap TOP_PID to avoid leaking the process.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a79c6740-f1a2-4db5-90e6-196bfaab4213

📥 Commits

Reviewing files that changed from the base of the PR and between d3436a0 and b0cfcdc.

📒 Files selected for processing (5)
  • tensorrt_llm/_utils.py
  • tensorrt_llm/executor/proxy.py
  • tensorrt_llm/executor/worker.py
  • tests/integration/test_lists/test-db/l0_a10.yml
  • tests/unittest/_utils/test_anti_zombie.py

Comment thread tensorrt_llm/_utils.py
Comment thread tests/unittest/_utils/test_anti_zombie.py Outdated
@JunyiXu-nv
JunyiXu-nv force-pushed the dev-junyix-feat-anti-zombie branch 2 times, most recently from 2fa3dca to a0190df Compare July 15, 2026 06:00
@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59422 [ run ] triggered by Bot. Commit: a0190df Link to invocation

@BowenFu BowenFu left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected_parent_pid is tested but never passed by a caller — worker_main (worker.py:191) calls bare set_parent_death_signal(), so the arming-race self-kill never runs on a real path. Worth wiring the proxy PID for the spawn case, or noting it's deferred so it doesn't read as dead code.

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59422 [ run ] completed with state SUCCESS. Commit: a0190df
/LLM/main/L0_MergeRequest_PR pipeline #47892 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@JunyiXu-nv
JunyiXu-nv force-pushed the dev-junyix-feat-anti-zombie branch from 200ee4b to 43d6470 Compare July 16, 2026 14:16
@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

Comment thread tensorrt_llm/_utils.py Outdated
only covers the direct parent. Deeper / forked trees are handled by
``kill_process_tree``.
"""
import signal

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the lazy imports in set_parent_death_signal (signal, ctypes) and kill_process_tree (time, psutil) could be moved to the top of the file. signal, ctypes, and time are stdlib; ctypes is already partially imported at the top (from ctypes import byref). psutil is the only third-party dep here, but _utils.py already imports numpy, nvtx, and mpi4py unconditionally so the bar for lazy-importing it seems inconsistent.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion! Updated.

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59723 [ run ] triggered by Bot. Commit: 43d6470 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59723 [ run ] completed with state SUCCESS. Commit: 43d6470
/LLM/main/L0_MergeRequest_PR pipeline #48150 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60256 [ run ] completed with state SUCCESS. Commit: 92763ed
/LLM/main/L0_MergeRequest_PR pipeline #48617 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60557 [ run ] triggered by Bot. Commit: 92763ed Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60557 [ run ] completed with state SUCCESS. Commit: 92763ed
/LLM/main/L0_MergeRequest_PR pipeline #48868 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60713 [ run ] triggered by Bot. Commit: 92763ed Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60713 [ run ] completed with state FAILURE. Commit: 92763ed
/LLM/main/L0_MergeRequest_PR pipeline #49002 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

The CPU-Generic-arm CI stage invokes pytest with
-m 'cpu_only and not disabled', so tests without the cpu_only marker
are deselected and the stage exits with pytest code 5, which the outer
runner reports as 'AssertionError: failure reported in unittests'.

Add pytest.mark.cpu_only alongside the existing linux-only skipif so
the four tests in tests/unittest/_utils/test_anti_zombie.py are
actually selected on the CPU stages.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60725 [ run ] triggered by Bot. Commit: 2f1bfa9 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60725 [ run ] completed with state FAILURE. Commit: 2f1bfa9
/LLM/main/L0_MergeRequest_PR pipeline #49012 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60867 [ run ] triggered by Bot. Commit: 2f1bfa9 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60867 [ run ] completed with state FAILURE. Commit: 2f1bfa9
/LLM/main/L0_MergeRequest_PR pipeline #49139 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

Resolve conflicts:
- tensorrt_llm/executor/proxy.py: keep both the anti-zombie
  kill_process_tree call at the end of pre_shutdown() and the new
  _get_next_client_id / _cleanup_multi_frontend_ipc_dir methods added
  on main.
- tests/integration/test_lists/test-db/l0_cpu_x86.yml: keep both the
  new test_anti_zombie.py entry and the new test_multi_frontend_routing.py
  entry.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
Addresses review nit from @brnguyen2: signal, ctypes, time (stdlib) and
psutil (third-party) were lazily imported inside set_parent_death_signal
and kill_process_tree. Move them to the module-level imports for
consistency with the rest of _utils.py, which already imports numpy,
nvtx, mpi4py unconditionally.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
@JunyiXu-nv
JunyiXu-nv force-pushed the dev-junyix-feat-anti-zombie branch from a0bc207 to 457a7d7 Compare July 23, 2026 02:54
@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61179 [ run ] triggered by Bot. Commit: 457a7d7 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61179 [ run ] completed with state FAILURE. Commit: 457a7d7
/LLM/main/L0_MergeRequest_PR pipeline #49428 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61478 [ run ] triggered by Bot. Commit: 457a7d7 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61478 [ run ] completed with state SUCCESS. Commit: 457a7d7
/LLM/main/L0_MergeRequest_PR pipeline #49701 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61686 [ run ] triggered by Bot. Commit: 457a7d7 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61686 [ run ] completed with state FAILURE. Commit: 457a7d7
/LLM/main/L0_MergeRequest_PR pipeline #49892 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@JunyiXu-nv

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61694 [ run ] triggered by Bot. Commit: 457a7d7 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61694 [ run ] completed with state FAILURE. Commit: 457a7d7
/LLM/main/L0_MergeRequest_PR pipeline #49899 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

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.

6 participants