Enable `debug_mode` for `subint_forkserver`

The `subint_forkserver` backend's child runtime is trio-native (uses
`_trio_main` + receives `SpawnSpec` over IPC just like `trio`/`subint`),
so `tractor.devx.debug._tty_lock` works in those subactors. Wire the
runtime gates that historically hard-coded `_spawn_method == 'trio'` to
recognize this third backend.

Deats,
- new `_DEBUG_COMPATIBLE_BACKENDS` module-const in `tractor._root`
  listing the spawn backends whose subactor runtime is trio-native
  (`'trio'`, `'subint_forkserver'`). Both the enable-site
  (`_runtime_vars['_debug_mode'] = True`) and the cleanup-site reset
  key.
  off the same tuple — keep them in lockstep when adding backends
- `open_root_actor`'s `RuntimeError` for unsupported backends now
  reports the full compatible-set + the rejected method instead of the
  stale "only `trio`" msg.
- `runtime._runtime.Actor._from_parent`'s SpawnSpec-recv gate adds
  `'subint_forkserver'` to the existing `('trio', 'subint')` tuple
  — fork child-side runtime receives the same SpawnSpec IPC handshake as
  the others.
- `subint_forkserver_proc` child-target now passes
  `spawn_method='subint_forkserver'` (was hard-coded `'trio'`) so
  `Actor.pformat()` / log lines reflect the actual parent-side spawn
  mechanism rather than masquerading as plain `trio`.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Gud Boi 2026-04-23 11:39:42 -04:00
parent 4227eabcba
commit 72d1b9016a
2 changed files with 31 additions and 4 deletions

View File

@ -69,6 +69,20 @@ from ._exceptions import (
logger = log.get_logger('tractor')
# Spawn backends under which `debug_mode=True` is supported.
# Requirement: the spawned subactor's root runtime must be
# trio-native so `tractor.devx.debug._tty_lock` works. Matches
# both the enable-site in `open_root_actor` and the cleanup-
# site reset of `_runtime_vars['_debug_mode']` — keep them in
# lockstep when adding backends.
_DEBUG_COMPATIBLE_BACKENDS: tuple[str, ...] = (
'trio',
# forkserver children run `_trio_main` in their own OS
# process — same child-side runtime shape as `trio_proc`.
'subint_forkserver',
)
# TODO: stick this in a `@acm` defined in `devx.debug`?
# -[ ] also maybe consider making this a `wrapt`-deco to
# save an indent level?
@ -293,10 +307,14 @@ async def open_root_actor(
)
loglevel: str = loglevel.upper()
# Debug-mode is currently only supported for backends whose
# subactor root runtime is trio-native (so `tractor.devx.
# debug._tty_lock` works). See `_DEBUG_COMPATIBLE_BACKENDS`
# module-const for the list.
if (
debug_mode
and
_spawn._spawn_method == 'trio'
_spawn._spawn_method in _DEBUG_COMPATIBLE_BACKENDS
):
_state._runtime_vars['_debug_mode'] = True
@ -318,7 +336,9 @@ async def open_root_actor(
elif debug_mode:
raise RuntimeError(
"Debug mode is only supported for the `trio` backend!"
f'Debug mode currently supported only for '
f'{_DEBUG_COMPATIBLE_BACKENDS!r} spawn backends, not '
f'{_spawn._spawn_method!r}.'
)
assert loglevel
@ -619,7 +639,7 @@ async def open_root_actor(
if (
debug_mode
and
_spawn._spawn_method == 'trio'
_spawn._spawn_method in _DEBUG_COMPATIBLE_BACKENDS
):
_state._runtime_vars['_debug_mode'] = False

View File

@ -870,7 +870,14 @@ class Actor:
accept_addrs: list[UnwrappedAddress]|None = None
if self._spawn_method in ("trio", "subint"):
if self._spawn_method in (
'trio',
'subint',
# `subint_forkserver` parent-side sends a
# `SpawnSpec` over IPC just like the other two
# — fork child-side runtime is trio-native.
'subint_forkserver',
):
# Receive post-spawn runtime state from our parent.
spawnspec: msgtypes.SpawnSpec = await chan.recv()