Compare commits
2 Commits
98bc642e72
...
f136063239
| Author | SHA1 | Date |
|---|---|---|
|
|
f136063239 | |
|
|
80ce54aeb1 |
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ Semantics worth knowing:
|
||||||
- it blocks until the remote task returns, re-raising any
|
- it blocks until the remote task returns, re-raising any
|
||||||
remote error in the usual boxed form right in the calling
|
remote error in the usual boxed form right in the calling
|
||||||
task.
|
task.
|
||||||
- placement also determines process ownership: ``an=`` spawns and
|
- lifetime mode also determines process ownership: ``an=`` spawns and
|
||||||
reaps a fresh child in an existing actor nursery, while passing
|
reaps a fresh child in an existing actor nursery, while passing
|
||||||
neither does the same in a private call-scoped nursery (booting
|
neither does the same in a private call-scoped nursery (booting
|
||||||
the runtime if needed). ``portal=`` instead runs one linked task
|
the runtime if needed). ``portal=`` instead runs one linked task
|
||||||
|
|
@ -108,7 +108,7 @@ Semantics worth knowing:
|
||||||
the portal's owner remains responsible for its lifetime.
|
the portal's owner remains responsible for its lifetime.
|
||||||
- concurrency composes the plain ``trio`` way: schedule
|
- concurrency composes the plain ``trio`` way: schedule
|
||||||
multiple ``run()`` calls into a local task nursery (see
|
multiple ``run()`` calls into a local task nursery (see
|
||||||
``examples/parallelism/to_actor_one_shots.py``).
|
``examples/parallelism/concurrent_toactor_primes.py``).
|
||||||
|
|
||||||
A reused actor must expose both the target module and the
|
A reused actor must expose both the target module and the
|
||||||
``to_actor`` context trampoline:
|
``to_actor`` context trampoline:
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,12 @@ async def main():
|
||||||
for name in ('donny', 'gretchen')
|
for name in ('donny', 'gretchen')
|
||||||
}
|
}
|
||||||
|
|
||||||
async def run_and_print(name: str, other_actor: str):
|
async def run_and_print(
|
||||||
|
name: str,
|
||||||
|
other_actor: str,
|
||||||
|
) -> None:
|
||||||
print(
|
print(
|
||||||
|
# RPC through an existing actor's `Portal`.
|
||||||
await portals[name].run(
|
await portals[name].run(
|
||||||
say_hello,
|
say_hello,
|
||||||
other_actor=other_actor,
|
other_actor=other_actor,
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ async def spawn_until(depth=0):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Let the background one-shot enter `breakpoint_forever()`
|
||||||
|
# before its sibling raises and cancellation propagates.
|
||||||
await trio.sleep(0.5)
|
await trio.sleep(0.5)
|
||||||
# rx and propagate error from child
|
# rx and propagate error from child
|
||||||
await tractor.to_actor.run(
|
await tractor.to_actor.run(
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ async def main():
|
||||||
async with (
|
async with (
|
||||||
tractor.open_nursery(
|
tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
enable_transports=['uds'], # TODO, apss this via osenv?
|
enable_transports=['uds'], # TODO, pass this via osenv?
|
||||||
loglevel='devx', # XXX, required for test!
|
loglevel='devx', # XXX, required for test!
|
||||||
) as an,
|
) as an,
|
||||||
trio.open_nursery() as tn,
|
trio.open_nursery() as tn,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
'''
|
'''
|
||||||
`tractor.to_actor.run()`: one-shot single-task subactor
|
`tractor.to_actor.run()`: concurrent one-shot prime checks
|
||||||
invocation, the SC-parallelism sibling of
|
invocation, the SC-parallelism sibling of
|
||||||
`trio.to_thread.run_sync()` (and `anyio.to_process`).
|
`trio.to_thread.run_sync()` (and `anyio.to_process`).
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ async def main():
|
||||||
tn.start_soon(burn_cpu)
|
tn.start_soon(burn_cpu)
|
||||||
|
|
||||||
# run the same func as the lone task in a subactor,
|
# run the same func as the lone task in a subactor,
|
||||||
# block on (and collect) its result
|
# block on and collect its PID as the caller-side result
|
||||||
pid = await tractor.to_actor.run(burn_cpu)
|
pid = await tractor.to_actor.run(burn_cpu)
|
||||||
|
|
||||||
print(f"Collected subproc {pid}")
|
print(f"Collected subproc {pid}")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue