Fix review nits from PR #460 self-review

Address the actionable findings from the `/code-review` pass
(#1-6); the d2-ext + docstring nits (#7-10) are left for a
follow-up.

Deats,
- `uds_transport_actor_tree.py`: `portal.chan.raddr.sockpath` is
  the *shared listener* socket (named for the root registrar), NOT
  the child's path — relabel it + lead with the per-child peer pid,
  and stop claiming it's the child addr in the docstring,
- `docs.yml`: scope the `pages` `concurrency` group to the `deploy`
  job w/ `cancel-in-progress: false` so a PR build can't cancel an
  in-flight production deploy,
- `architecture.rst`: `'subint'` is not a selectable `start_method`
  on this branch (`SpawnMethodKey` lacks it) — reframe as
  in-development/roadmap,
- `context.rst`: `StreamOverrun` isn't re-exported from `tractor`;
  point at `tractor._exceptions`,
- `debugging/`: sweep the 3 literalinclude'd examples off the
  deprecated `.result()` -> `.wait_for_result()`,
- `quickstart.rst`: proc-title is `name@pid` (per `Aid.reprol`),
  not `@uuid`.

NOTE, the `debugging/` examples are pexpect-tested; re-run
`tests/devx/test_debugger.py` for them.

(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-06-25 17:07:44 -04:00
parent ea982875a5
commit 37e7470f26
8 changed files with 32 additions and 25 deletions

View File

@ -17,11 +17,6 @@ permissions:
pages: write
id-token: write
# never run >1 pages deploy at once
concurrency:
group: 'pages'
cancel-in-progress: true
jobs:
build:
name: 'sphinx build'
@ -52,6 +47,12 @@ jobs:
name: 'deploy to gh-pages'
if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
needs: build
# serialize deploys but NEVER cancel an in-flight one
# mid-upload; queue the next instead (scoped to this job so
# PR builds can't cancel a production deploy).
concurrency:
group: 'pages'
cancel-in-progress: false
runs-on: ubuntu-latest
environment:
name: github-pages

View File

@ -192,13 +192,14 @@ spawn backend, selected with the ``start_method`` kwarg to
names (forkserver is posix-only). Mostly interesting for
ecosystem compat and start-up-latency tuning.
``'subint'`` (experimental, py3.14+)
Each actor runs as a `PEP 734`_ sub-interpreter
(``concurrent.interpreters``) driven on its own OS thread
*inside the parent process*: interpreter-level
shared-nothing isolation with much faster start-up. Yes,
this bends the one-actor-one-process rule; the rest of the
model is unchanged.
``'subint'`` (in development, py3.14+)
On the roadmap (not yet selectable via ``start_method`` on
this release): run each actor as a `PEP 734`_
sub-interpreter (``concurrent.interpreters``) driven on its
own OS thread *inside the parent process* — interpreter-level
shared-nothing isolation with much faster start-up. Yes, this
bends the one-actor-one-process rule; the rest of the model
is unchanged.
The ``TRACTOR_SPAWN_METHOD`` env-var beats any caller-passed
``start_method``, so you can swap backends under an unmodified

View File

@ -302,9 +302,9 @@ Overruns and backpressure
Stream msgs land in a bounded per-context buffer on the receiver
side. A sender that outpaces a non-consuming receiver *overruns*
it and the runtime raises :exc:`tractor.StreamOverrun` (also a
:exc:`trio.TooSlowError`) instead of buffering without bound — SC
discipline applies to memory too.
it and the runtime raises ``StreamOverrun`` (from
``tractor._exceptions``; also a :exc:`trio.TooSlowError`) instead
of buffering without bound — SC discipline applies to memory too.
Your knobs:

View File

@ -141,7 +141,7 @@ breakfast - run this while monitoring your process tree::
Every subactor (best-effort, via the optional
``setproctitle`` dep) re-titles its OS process like
``_subactor[worker_0@<uuid>]``, so ``pstree``/``htop``/
``_subactor[worker_0@<pid>]``, so ``pstree``/``htop``/
``pgrep -f`` can tell your actors apart at a glance.
You'll see something like::

View File

@ -78,7 +78,7 @@ async def main():
portal: tractor.Portal = await n.run_in_actor(
cancelled_before_pause,
)
await portal.result()
await portal.wait_for_result()
# ensure the same works in the root actor!
await pm_on_cancelled()

View File

@ -22,7 +22,7 @@ async def main():
portal = await n.run_in_actor(
breakpoint_forever,
)
await portal.result()
await portal.wait_for_result()
if __name__ == '__main__':

View File

@ -18,10 +18,10 @@ async def main():
p: tractor.Portal = await an.run_in_actor(name_error)
# with this style, should raise on this line
await p.result()
await p.wait_for_result()
# with this alt style should raise at `open_nusery()`
# return await p.result()
# return await p.wait_for_result()
if __name__ == '__main__':

View File

@ -4,9 +4,9 @@ Demonstrate an actor tree which talks over unix-domain-socket
`enable_transports=['uds']` when opening the root and every
subactor inherits the preference.
The child's channel address is a filesystem socket path (no
TCP port in sight!) and, as a kernel-provided bonus, the
peer's pid is exchanged for free via `SO_PEERCRED`.
Every channel address is a filesystem socket path (no TCP port
in sight!) and, as a kernel-provided bonus, the peer's pid is
exchanged for free via `SO_PEERCRED`.
'''
import os
@ -38,12 +38,17 @@ async def main() -> None:
# filesystem socket path, NOT a (host, port) pair!
raddr = portal.chan.raddr
assert raddr.proto_key == 'uds'
# NOTE, `.sockpath` is the *shared listener* socket file
# (named for the root registrar) this channel rode in
# on, NOT a per-child path; the child-specific identity
# we get for free is the kernel-reported peer pid (via
# `SO_PEERCRED`).
print(
f'portal chan tpt proto: {raddr.proto_key!r}\n'
f'portal chan sock file: {raddr.sockpath}\n'
f'listener sock file: {raddr.sockpath}\n'
f'kernel-reported peer pid: {raddr.maybe_pid}\n'
)
# ask the child for its own bind addr: also a
# ask the child for its OWN distinct bind addr: another
# socket-file path under the runtime dir.
print(f'child says: {await portal.run(report_addr)}')
await portal.cancel_actor()