Skip to content

Commit 85457cb

Browse files
goodboyclaude
andcommitted
Address Copilot review suggestions on PR #366
- Use `bidict.forceput()` in `register_actor()` to handle duplicate addr values from stale entries or actor restarts. - Fix `uid` annotation to `tuple[str, str]|None` in `maybe_open_portal()` and handle the `None` return from `delete_addr()` in log output. - Pass explicit `registry_addrs=[reg_addr]` to `open_nursery()` and `find_actor()` in `test_stale_entry_is_deleted` to ensure the test uses the remote registrar. - Update `query_actor()` docstring to document the new `(addr, reg_portal)` yield shape. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 850219f commit 85457cb

File tree

3 files changed

+29
-11
lines changed

3 files changed

+29
-11
lines changed

tests/test_discovery.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ async def main():
491491
async with (
492492
tractor.open_nursery(
493493
debug_mode=debug_mode,
494+
registry_addrs=[reg_addr],
494495
) as an,
495496
tractor.get_registry(reg_addr) as _reg_ptl,
496497
):
@@ -501,7 +502,10 @@ async def main():
501502
async with ptl.open_context(
502503
kill_transport,
503504
) as (first, ctx):
504-
async with tractor.find_actor(name) as maybe_portal:
505+
async with tractor.find_actor(
506+
name,
507+
registry_addrs=[reg_addr],
508+
) as maybe_portal:
505509
# because the transitive
506510
# `._discovery.maybe_open_portal()` call should
507511
# fail and implicitly call `.delete_addr()`

tractor/_discovery.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,12 @@ async def query_actor(
160160
Lookup a transport address (by actor name) via querying a registrar
161161
listening @ `regaddr`.
162162
163-
Returns the transport protocol (socket) address or `None` if no
164-
entry under that name exists.
163+
Yields a `tuple` of `(addr, reg_portal)` where,
164+
- `addr` is the transport protocol (socket) address or `None` if
165+
no entry under that name exists,
166+
- `reg_portal` is the `Portal` to the registrar used for the
167+
lookup (or `None` when the peer was found locally via
168+
`get_peer_by_name()`).
165169
166170
'''
167171
actor: Actor = current_actor()
@@ -225,16 +229,21 @@ async def maybe_open_portal(
225229
# NOTE: ensure we delete the stale entry
226230
# from the registrar actor when available.
227231
if reg_portal is not None:
228-
uid: tuple[str, str] = await reg_portal.run_from_ns(
232+
uid: tuple[str, str]|None = await reg_portal.run_from_ns(
229233
'self',
230234
'delete_addr',
231235
addr=addr,
232236
)
233-
log.warning(
234-
f'Deleted stale registry entry !\n'
235-
f'addr: {addr!r}\n'
236-
f'uid: {uid!r}\n'
237-
)
237+
if uid:
238+
log.warning(
239+
f'Deleted stale registry entry !\n'
240+
f'addr: {addr!r}\n'
241+
f'uid: {uid!r}\n'
242+
)
243+
else:
244+
log.warning(
245+
f'No registry entry found for addr: {addr!r}'
246+
)
238247
else:
239248
log.warning(
240249
f'Connection to {addr!r} failed'

tractor/_runtime.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,8 +2013,13 @@ async def register_actor(
20132013
# should never be 0-dynamic-os-alloc
20142014
await debug.pause()
20152015

2016-
# XXX NOTE, value must also be hashable.
2017-
self._registry[uid] = tuple(addr)
2016+
# XXX NOTE, value must also be hashable AND since
2017+
# `._registry` is a `bidict` values must be unique; use
2018+
# `.forceput()` to replace any prior (stale) entries
2019+
# that might map a different uid to the same addr (e.g.
2020+
# after an unclean shutdown or actor-restart reusing
2021+
# the same address).
2022+
self._registry.forceput(uid, tuple(addr))
20182023

20192024
# pop and signal all waiter events
20202025
events = self._waiters.pop(name, [])

0 commit comments

Comments
 (0)