Use `Aid` keys for child reap state

The fresh reap-coordination maps still used legacy `.uid` tuples even
though process monitors and channels carry complete `Aid` identities.
This extended the legacy key format into new private state.

Key both reap maps by `Aid` and derive `.uid` only when accessing the
existing `_children` map. UUID-based `Aid` hashing lets the subactor
and decoded channel identities resolve the same synchronization state.

Update registration tests to exercise the full identity keys.

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

Prompt-IO: ai/prompt-io/opencode/20260824T233957Z_5327b25e_prompt_io.md

(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
wkt/to_actor_subpkg
Gud Boi 2026-08-24 21:56:00 -04:00
parent 5327b25e1b
commit e42ecb559d
5 changed files with 87 additions and 18 deletions

View File

@ -0,0 +1,36 @@
---
model: openai/gpt-5.6-sol
service: opencode
session: d9d7df2c-7044-463f-8768-ec024718eac9
timestamp: 2026-08-24T23:39:57Z
git_ref: 5327b25e
scope: code
substantive: true
raw_file: 20260824T233957Z_5327b25e_prompt_io.raw.md
---
## Prompt
Continue PR #481 review remediation after committing the debugger-state
sampler. The human selected "keep" for the paired review request to use
`Aid` objects as keys in the newly added reap-coordination maps.
## Response summary
Migrate only `ActorNursery._child_reap_requests` and
`ActorNursery._child_reaped` to `Aid` keys. Preserve the legacy
`ActorNursery._children` `.uid` key and pass full actor identities
through the narrow process-monitor bookkeeping path.
## Files changed
- `tractor/runtime/_supervise.py` - key fresh reap maps by `Aid`.
- `tractor/spawn/_spawn.py` - pass `Aid` into completed-reap cleanup.
- `tests/test_to_actor.py` - exercise `Aid` registration keys.
## Human edits
The human explicitly selected "keep" after reviewing the scope,
performance, and mutability tradeoffs. The human retained the legacy
tuple key for `_children` and accepted `Aid` for only the two fresh
private mappings. No direct source-line edits were made by the human.

View File

@ -0,0 +1,27 @@
---
model: openai/gpt-5.6-sol
service: opencode
timestamp: 2026-08-24T23:39:57Z
git_ref: 5327b25e
diff_cmd: git diff HEAD~1..HEAD
---
Implement the approved PR #481 review update which uses `Aid` keys for
the two fresh `ActorNursery` reap-coordination maps while preserving the
legacy `.uid` key for `ActorNursery._children`.
> `git diff HEAD~1..HEAD -- tractor/runtime/_supervise.py`
Type and access `_child_reap_requests` and `_child_reaped` by `Aid`.
Pass full actor identities through registration, cancellation, and
completed-reap bookkeeping, deriving `.uid` only for `_children`.
> `git diff HEAD~1..HEAD -- tractor/spawn/_spawn.py`
Forward `subactor.aid` when publishing completed process teardown.
> `git diff HEAD~1..HEAD -- tests/test_to_actor.py`
Update deterministic registration tests to exercise `Aid` map keys.
Run focused registration/reaping tests and the full `to_actor` suite.

View File

@ -431,8 +431,8 @@ def test_late_child_registration_observes_cancel():
proc,
None,
)
assert an._child_reap_requests[aid.uid] is reap_request
assert an._child_reaped[aid.uid] is reaped
assert an._child_reap_requests[aid] is reap_request
assert an._child_reaped[aid] is reaped
def test_mp_late_registration_never_starts_process(
@ -521,9 +521,11 @@ def test_late_child_reap_registration_is_released():
an._child_reaped = {}
an._join_procs.set()
reap_request, _ = an._register_child_reap(
('late_child', 'uid'),
aid = tractor.msg.Aid(
name='late_child',
uuid='uid',
)
reap_request, _ = an._register_child_reap(aid)
assert reap_request.is_set()

View File

@ -46,6 +46,7 @@ from ..log import (
get_logger,
get_loglevel,
)
from ..msg import Aid
from ._runtime import Actor
from ._portal import Portal
from ..trionics import (
@ -246,11 +247,11 @@ class ActorNursery:
self._join_procs = trio.Event()
self._child_reap_requests: dict[
tuple[str, str],
Aid,
trio.Event,
] = {}
self._child_reaped: dict[
tuple[str, str],
Aid,
trio.Event,
] = {}
self._at_least_one_child_in_debug: bool = False
@ -319,7 +320,7 @@ class ActorNursery:
def _register_child_reap(
self,
uid: tuple[str, str],
aid: Aid,
) -> tuple[trio.Event, trio.Event]:
'''
Register a child monitor's process-reap events.
@ -327,8 +328,8 @@ class ActorNursery:
'''
reap_request = trio.Event()
reaped = trio.Event()
self._child_reap_requests[uid] = reap_request
self._child_reaped[uid] = reaped
self._child_reap_requests[aid] = reap_request
self._child_reaped[aid] = reaped
if self._join_procs.is_set():
reap_request.set()
return reap_request, reaped
@ -343,13 +344,14 @@ class ActorNursery:
Atomically publish one child and its reap coordination.
'''
uid: tuple[str, str] = subactor.aid.uid
aid: Aid = subactor.aid
uid: tuple[str, str] = aid.uid
self._children[uid] = (
subactor,
proc,
portal,
)
reap_request, reaped = self._register_child_reap(uid)
reap_request, reaped = self._register_child_reap(aid)
return (
reap_request,
reaped,
@ -369,18 +371,19 @@ class ActorNursery:
def _mark_child_reaped(
self,
uid: tuple[str, str],
aid: Aid,
) -> None:
'''
Publish completed child-process teardown to its waiter.
'''
uid: tuple[str, str] = aid.uid
self._children.pop(uid, None)
reap_request: trio.Event|None = (
self._child_reap_requests.pop(uid, None)
self._child_reap_requests.pop(aid, None)
)
reaped: trio.Event|None = self._child_reaped.pop(
uid,
aid,
None,
)
assert (
@ -399,14 +402,15 @@ class ActorNursery:
Cancel, join and unregister one nursery-owned child.
'''
uid: tuple[str, str] = portal.channel.aid.uid
aid: Aid = portal.channel.aid
uid: tuple[str, str] = aid.uid
child_entry = self._children.get(uid)
if child_entry is None:
return
subactor, proc, _ = child_entry
reap_request: trio.Event = self._child_reap_requests[uid]
reaped: trio.Event = self._child_reaped[uid]
reap_request: trio.Event = self._child_reap_requests[aid]
reaped: trio.Event = self._child_reaped[aid]
with trio.CancelScope(shield=True):
try:

View File

@ -460,7 +460,7 @@ async def new_proc(
proc_kwargs=proc_kwargs
)
finally:
actor_nursery._mark_child_reaped(subactor.aid.uid)
actor_nursery._mark_child_reaped(subactor.aid)
# NOTE: bottom-of-module to avoid a circular import since the