Clarify owned-child hard-reap docs

Match the cancellation guide, `Portal.cancel_actor()` contract and
duplicate-name regression comments to the actor-nursery impl: a failed
bounded cancel request escalates directly to `proc.kill()`.

Keep the older terminate-then-kill path documented separately for its
remaining legacy callers.

Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328

(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
wkt/to_actor_subpkg
Gud Boi 2026-08-25 15:56:38 -04:00
parent 80ce54aeb1
commit f136063239
3 changed files with 12 additions and 11 deletions

View File

@ -230,22 +230,23 @@ Graceful first, hard as a last resort
The hard-kill path is *skipped* whenever an actor in the tree The hard-kill path is *skipped* whenever an actor in the tree
holds the debug-REPL lock (``debug_mode=True`` flavors): holds the debug-REPL lock (``debug_mode=True`` flavors):
SIGTERM raining down on a tree mid-``pdb`` session would Process signals raining down on a tree mid-``pdb`` session would
clobber your prompt. See :doc:`/guide/debugging`. clobber your prompt. See :doc:`/guide/debugging`.
Every process teardown in ``tractor`` walks the same escalation Owned-child teardown in ``tractor`` begins with the same graceful
ladder, top rung first, steps, then selects the escalation path used by its supervisor,
1. **graceful cancel request**: a runtime-cancel msg over IPC; the 1. **graceful cancel request**: a runtime-cancel msg over IPC; the
target actor cancels its tasks, closes its channels and exits target actor cancels its tasks, closes its channels and exits
its :func:`trio.run` cleanly, its :func:`trio.run` cleanly,
2. **soft wait**: the parent waits (bounded) for the child process 2. **soft wait**: the parent waits (bounded) for the child process
to exit on its own, to exit on its own,
3. **SIGTERM**: no ack within the bounded wait (internally an 3. **actor-nursery hard reap**: no cancel ack within the bounded wait
``ActorTooSlowError``) escalates to ``proc.terminate()``, (internally an ``ActorTooSlowError``) escalates directly to
4. **SIGKILL ultimatum**: still alive after the hard-kill timeout ``proc.kill()`` before the child monitor joins the process,
(~1.6s)? The runtime logs that the "T-800" has been deployed to 4. **legacy soft-kill path**: older teardown callers may first issue
collect the zombie and issues ``proc.kill()``. No survivors. ``proc.terminate()`` and then deploy the "T-800" ``proc.kill()``
ultimatum if the process survives that additional bounded wait.
The result is the **no-zombies guarantee**: ``tractor`` tries to The result is the **no-zombies guarantee**: ``tractor`` tries to
protect you from zombies, no matter what. Quoting the project protect you from zombies, no matter what. Quoting the project

View File

@ -207,7 +207,7 @@ def test_dup_name_cancel_cascade_escalates_to_hard_kill(
Post-fix, `Portal.cancel_actor()` raises `ActorTooSlowError` on Post-fix, `Portal.cancel_actor()` raises `ActorTooSlowError` on
the bounded-wait timeout, and `ActorNursery.cancel()`'s the bounded-wait timeout, and `ActorNursery.cancel()`'s
per-child wrapper escalates to `proc.terminate()` (hard-kill). per-child wrapper escalates directly to `proc.kill()` (hard-reap).
The full nursery teardown therefore stays bounded even under The full nursery teardown therefore stays bounded even under
pathological timing. pathological timing.
@ -266,7 +266,7 @@ def test_dup_name_cancel_cascade_escalates_to_hard_kill(
# post-teardown sanity: every child proc must be reaped. # post-teardown sanity: every child proc must be reaped.
# If escalation worked, even timed-out cancel-RPCs would # If escalation worked, even timed-out cancel-RPCs would
# have triggered `proc.terminate()` and the procs are dead. # have triggered `proc.kill()` and the procs are dead.
for p in portals: for p in portals:
# `Portal.channel.connected()` -> False once the # `Portal.channel.connected()` -> False once the
# underlying chan disconnected (clean exit OR # underlying chan disconnected (clean exit OR

View File

@ -292,7 +292,7 @@ class Portal:
- `True`: on bounded-wait expiry, raise `ActorTooSlowError` - `True`: on bounded-wait expiry, raise `ActorTooSlowError`
so the caller MUST handle the failure explicitly. so the caller MUST handle the failure explicitly.
`ActorNursery.cancel()` opts in so it can escalate via `ActorNursery.cancel()` opts in so it can escalate via
`proc.terminate()` per SC-discipline. direct `proc.kill()` hard-reaping per SC-discipline.
''' '''
__runtimeframe__: int = 1 # noqa __runtimeframe__: int = 1 # noqa