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
parent
ea982875a5
commit
37e7470f26
|
|
@ -17,11 +17,6 @@ permissions:
|
||||||
pages: write
|
pages: write
|
||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
# never run >1 pages deploy at once
|
|
||||||
concurrency:
|
|
||||||
group: 'pages'
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: 'sphinx build'
|
name: 'sphinx build'
|
||||||
|
|
@ -52,6 +47,12 @@ jobs:
|
||||||
name: 'deploy to gh-pages'
|
name: 'deploy to gh-pages'
|
||||||
if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
|
if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
|
||||||
needs: build
|
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
|
runs-on: ubuntu-latest
|
||||||
environment:
|
environment:
|
||||||
name: github-pages
|
name: github-pages
|
||||||
|
|
|
||||||
|
|
@ -192,13 +192,14 @@ spawn backend, selected with the ``start_method`` kwarg to
|
||||||
names (forkserver is posix-only). Mostly interesting for
|
names (forkserver is posix-only). Mostly interesting for
|
||||||
ecosystem compat and start-up-latency tuning.
|
ecosystem compat and start-up-latency tuning.
|
||||||
|
|
||||||
``'subint'`` (experimental, py3.14+)
|
``'subint'`` (in development, py3.14+)
|
||||||
Each actor runs as a `PEP 734`_ sub-interpreter
|
On the roadmap (not yet selectable via ``start_method`` on
|
||||||
(``concurrent.interpreters``) driven on its own OS thread
|
this release): run each actor as a `PEP 734`_
|
||||||
*inside the parent process*: interpreter-level
|
sub-interpreter (``concurrent.interpreters``) driven on its
|
||||||
shared-nothing isolation with much faster start-up. Yes,
|
own OS thread *inside the parent process* — interpreter-level
|
||||||
this bends the one-actor-one-process rule; the rest of the
|
shared-nothing isolation with much faster start-up. Yes, this
|
||||||
model is unchanged.
|
bends the one-actor-one-process rule; the rest of the model
|
||||||
|
is unchanged.
|
||||||
|
|
||||||
The ``TRACTOR_SPAWN_METHOD`` env-var beats any caller-passed
|
The ``TRACTOR_SPAWN_METHOD`` env-var beats any caller-passed
|
||||||
``start_method``, so you can swap backends under an unmodified
|
``start_method``, so you can swap backends under an unmodified
|
||||||
|
|
|
||||||
|
|
@ -302,9 +302,9 @@ Overruns and backpressure
|
||||||
|
|
||||||
Stream msgs land in a bounded per-context buffer on the receiver
|
Stream msgs land in a bounded per-context buffer on the receiver
|
||||||
side. A sender that outpaces a non-consuming receiver *overruns*
|
side. A sender that outpaces a non-consuming receiver *overruns*
|
||||||
it and the runtime raises :exc:`tractor.StreamOverrun` (also a
|
it and the runtime raises ``StreamOverrun`` (from
|
||||||
:exc:`trio.TooSlowError`) instead of buffering without bound — SC
|
``tractor._exceptions``; also a :exc:`trio.TooSlowError`) instead
|
||||||
discipline applies to memory too.
|
of buffering without bound — SC discipline applies to memory too.
|
||||||
|
|
||||||
Your knobs:
|
Your knobs:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ breakfast - run this while monitoring your process tree::
|
||||||
|
|
||||||
Every subactor (best-effort, via the optional
|
Every subactor (best-effort, via the optional
|
||||||
``setproctitle`` dep) re-titles its OS process like
|
``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.
|
``pgrep -f`` can tell your actors apart at a glance.
|
||||||
|
|
||||||
You'll see something like::
|
You'll see something like::
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ async def main():
|
||||||
portal: tractor.Portal = await n.run_in_actor(
|
portal: tractor.Portal = await n.run_in_actor(
|
||||||
cancelled_before_pause,
|
cancelled_before_pause,
|
||||||
)
|
)
|
||||||
await portal.result()
|
await portal.wait_for_result()
|
||||||
|
|
||||||
# ensure the same works in the root actor!
|
# ensure the same works in the root actor!
|
||||||
await pm_on_cancelled()
|
await pm_on_cancelled()
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ async def main():
|
||||||
portal = await n.run_in_actor(
|
portal = await n.run_in_actor(
|
||||||
breakpoint_forever,
|
breakpoint_forever,
|
||||||
)
|
)
|
||||||
await portal.result()
|
await portal.wait_for_result()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ async def main():
|
||||||
p: tractor.Portal = await an.run_in_actor(name_error)
|
p: tractor.Portal = await an.run_in_actor(name_error)
|
||||||
|
|
||||||
# with this style, should raise on this line
|
# 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()`
|
# with this alt style should raise at `open_nusery()`
|
||||||
# return await p.result()
|
# return await p.wait_for_result()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ Demonstrate an actor tree which talks over unix-domain-socket
|
||||||
`enable_transports=['uds']` when opening the root and every
|
`enable_transports=['uds']` when opening the root and every
|
||||||
subactor inherits the preference.
|
subactor inherits the preference.
|
||||||
|
|
||||||
The child's channel address is a filesystem socket path (no
|
Every channel address is a filesystem socket path (no TCP port
|
||||||
TCP port in sight!) and, as a kernel-provided bonus, the
|
in sight!) and, as a kernel-provided bonus, the peer's pid is
|
||||||
peer's pid is exchanged for free via `SO_PEERCRED`.
|
exchanged for free via `SO_PEERCRED`.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
import os
|
import os
|
||||||
|
|
@ -38,12 +38,17 @@ async def main() -> None:
|
||||||
# filesystem socket path, NOT a (host, port) pair!
|
# filesystem socket path, NOT a (host, port) pair!
|
||||||
raddr = portal.chan.raddr
|
raddr = portal.chan.raddr
|
||||||
assert raddr.proto_key == 'uds'
|
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(
|
print(
|
||||||
f'portal chan tpt proto: {raddr.proto_key!r}\n'
|
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'
|
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.
|
# socket-file path under the runtime dir.
|
||||||
print(f'child says: {await portal.run(report_addr)}')
|
print(f'child says: {await portal.run(report_addr)}')
|
||||||
await portal.cancel_actor()
|
await portal.cancel_actor()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue