From 007b45857b17aac5cb71d4cb32932c09b657b878 Mon Sep 17 00:00:00 2001 From: goodboy Date: Tue, 7 Apr 2026 00:47:53 -0400 Subject: [PATCH] Revert `resources.pop()` back inside `run_ctx` inner finally Reverts the `_Cache.run_ctx` change from 93aa39db which moved `resources.pop(ctx_key)` to an outer `finally` *after* the acm's `__aexit__()`. That introduced an atomicity gap: `values` was already popped in the inner finally but `resources` survived through the acm teardown checkpoints. A re-entering task that creates a fresh lock (the old one having been popped by the exiting caller) could then acquire immediately and find stale `resources` (for which now we raise a `RuntimeError('Caching resources ALREADY exist?!')`). Deats, - the orig 93aa39db rationale was a preemptive guard against acm `__aexit__()` code accessing `_Cache` mid-teardown, but no `@acm` in `tractor` (or `piker`) ever does that; the scenario never materialized. - by popping both `values` AND `resources` atomically (no checkpoint between them) in the inner finally, the re-entry race window is closed: either the new task sees both entries (cache hit) or neither (clean cache miss). - `test_moc_reentry_during_teardown` now passes without `xfail`! (:party:) (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code --- tractor/trionics/_mngrs.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/tractor/trionics/_mngrs.py b/tractor/trionics/_mngrs.py index 34e62a7c..cff21767 100644 --- a/tractor/trionics/_mngrs.py +++ b/tractor/trionics/_mngrs.py @@ -227,22 +227,15 @@ class _Cache: task_status: trio.TaskStatus[T] = trio.TASK_STATUS_IGNORED, ) -> None: - try: - async with mng as value: - _, no_more_users = cls.resources[ctx_key] - try: - cls.values[ctx_key] = value - task_status.started(value) - await no_more_users.wait() - finally: - value = cls.values.pop(ctx_key) - finally: - # discard nursery ref so it won't be re-used (an error)? - _rsrcs = cls.resources.pop(ctx_key) - log.error( - f'Popping ctx resources\n' - f'{_rsrcs}\n' - ) + async with mng as value: + _, no_more_users = cls.resources[ctx_key] + cls.values[ctx_key] = value + task_status.started(value) + try: + await no_more_users.wait() + finally: + value = cls.values.pop(ctx_key) + cls.resources.pop(ctx_key) class _UnresolvedCtx: