The Structural Dynamics of Flow: finally a formalized modular transport layer -> tractor.ipc 😎 #375
The Structural Dynamics of Flow: finally a formalized modular transport layer -> tractor.ipc 😎 #375
tractor.ipc 😎 #375Conversation
|
Lol well first thing is getting |
|
The IPC server subsys is fully factored in close-to-original form as of now 🥳 I'd still like to get the per- So that would be |
Shared memory array API and optional tight integration with `numpy` Landing this so many downstream major feature branches depend on it namely, - #375 - #376 - and the eventual https://pikers.dev/goodboy/tractor/pulls/10
|
There changed base to |
salotz
left a comment
There was a problem hiding this comment.
I appreciate being added and glad to see work is being done here. I'm a bit far from this in my current engagements, but I'll cheer on the side lines :)
EventFD class now expects the fd to already be init with open_eventfd RingBuff Sender and Receiver fully manage SharedMemory and EventFD lifecycles, no aditional ctx mngrs needed Separate ring buf tests into its own test bed Add parametrization to test and cancellation Add docstrings Add simple testing data gen module .samples
…racker to its own _mp_bs module
…les under tractor.ipc
As much as is possible given we currently do some graceful cancellation join-waiting on any connected sub-actors whenever an active `local_nursery: AcrtorNursery` in the post-rpc teardown sequence of `handle_stream_from_peer()` is detected. In such cases we try to allow the higher level inter-actor (task) context(s) to fully cancelled-ack before conducting IPC machinery shutdown. The main immediate motivation for all this is to support unit testing the `.ipc._server` APIs but in the future may be useful for anyone wanting to use our modular IPC transport layer sin-"actors". Impl deats, - drop passing an `actor: Actor` ref from as many routines in `.ipc._server` as possible instead opting to use `._state.current_actor()` where abs needed; thus the fns dropping an `actor` input param are: - `open_ipc_server()` - `IPCServer.listen_on()` - `._serve_ipc_eps()` - `.handle_stream_from_peer()` - factor the above mentioned graceful remote-cancel-ack waiting into a new `maybe_wait_on_canced_subs()` which is called from `handle_stream_from_peer()` and delivers a maybe-`local_nursery: ActorNursery` for downstream logic; it's this new fn which primarily still needs to call `current_actor()`. - in `handle_stream_from_peer()` also use `current_actor()` to check if a handshake is needed (or if it was called as part of some actor-runtime-less operation like our unit test suite!). - also don't pass an `actor` to `._rpc.process_messages()` see how-n-why below.. Surrounding ipc-server client/caller adjustments, - `._rpc.process_messages()` no longer takes an `actor` input and now calls `current_actor()` instead. - `._portal.open_portal()` is adjusted to ^. - `._runtime.async_main()` is adjusted to the `.ipc._server`'s removal of `actor` ref passing. Also, - drop some server `log.info()`s to `.runtime()`
As per the outstanding TODO just above the redic `setattr()` loop in `Actor._from_parent()`!! Instead of all that risk-ay monkeying, add detailed comment-sections around each explicit assignment of each `SpawnSpec` field, including those that were already being explicitly set. Those and other deats, - ONLY enable the `.devx._debug` (CHERRY-CONFLICT: later changed to `.debug._tty_lock`) module from `Actor.__init__()` in the root actor. - ONLY enable the `.devx.debug._tty_lock` module from `Actor.__init__()` in the root actor. - add a new `get_mod_nsps2fps()` to replace the loop in init and assign the initial `.enable_modules: dict[str, str]` from it. - do `self.enable_modules.update(spawnspec.enable_modules)` instead of an overwrite and assert the table is by default empty in all subs.
Buncha either new AOTc lib whls and they added an `upload-time` field.
Actually applying the input it in the root as well as all sub-actors by
passing it down to sub-actors through runtime-vars as delivered by the
initial `SpawnSpec` msg during child runtime init.
Impl deats,
- add a new `_state._runtime_vars['_enable_tpts']: list[str]` field set
by the input param (if provided) to `.open_root_actor()`.
- mk `current_ipc_protos()` return the runtime-var entry with instead
the default in the `_runtime_vars: dict` set to `[_def_tpt_proto]`.
- in `.open_root_actor()`, still error on this being a >1 `list[str]`
until we have more testing infra/suites to audit multi-protos per
actor.
- return the new value (as 3rd element) from `Actor._from_parent()` as
per the todo note; means `_runtime.async_main()` will allocate
`accept_addrs` as tpt-specific `Address` entries and pass them to
`IPCServer.listen_on()`.
Also,
- also add a new `_state._runtime_vars['_root_addrs']: list = []` field
with the intent of fully replacing the `'_root_mailbox'` field since,
* it will need to be a collection to support multi-tpt,
* it's a more cohesive field name alongside `_registry_addrs`,
* the root actor of every tree needs to have a dedicated addr set
(separate from any host-singleton registry actor) so that all its
subs can contact it for capabilities mgmt including debugger
access/locking.
- in the root, populate the field in `._runtime.async_main()` and for
now just set '_root_mailbox' to the first entry in that list in
anticipation of future multi-homing/transport support.
Both via a post-init method to validate the original input `._host: str` and in `.is_valid` to ensure the host-part isn't something, esoteric..
fbc9325 to
27e6ad1
Compare
|
Welp just force pushed after a bunch of rebasing to get in as much of the final impl minus testing (which will come in a follow up patchset). |
See docs: https://docs.astral.sh/uv/guides/integration/github/ Summary, - drop `mypy` job for now since I'd like to move to trying `ty`. - convert sdist built to `uv build` - just run test suite on py3.13 for now, not sure if 3.12 will break due to the eg stuff or not?
Oddly my env was borked bc a missing sub-dep (`typing-extensions` apparently not added by `uv` for `stackscope`?) and then `stackscope` was silently failing import and caused the shield-pause test to also fail (since it couldn't match the expected `log.devx()` on console). The import failure is not very explanatory due to the `log.warning()`; change it to `.error()` level. Also, explicitly import `_sync_pause_from_builtin` in `examples/debugging/restore_builtin_breakpoint.py` to ensure the ref is exported properly from `.devx.debug` (which it wasn't during dev of the prior commit Bp).
Bc this history is pre `.devx.debug` subpkg creation..
|
Ehyyo, we green in CI with |
|
See #381 for |
|
New badge links added to the readme.. though let's see if it flips green 🙏🏼 |
|
Eyyyo***2, guess she's ready B) |
Although most of this work transpired on an alt (and now quite
distributed) set of (sometimes-private) git hosting services, we
figured getting some lurker hype going again on the project couldn't
hurt.
This initial
tractor.ipceffort was spearheaded by our very own@guilledk surrounding their work on a new linux-only high-performance
impl of a shared-mem ring-buffer with native
trioasync blockingsupport/semantics using
eventfd😎The longstanding original idea was to get a more generic and
performant, soft-real-time targeting,
ShmList-like interface whichdoes not require read/write event signalling over another IPC
transport (like TCP as was the case with the current state of things
in #338).
That ringbuf code will now land later on top of this history sinceI've made a buncha of reworks and refinements to that original attempt
at modularizing our IPC transport layering.
Those original ideas along with many others are being published in
a hot new lib which
you should all checkout once it refines/matures a bit 😉
Details on what's actually landing here below!
The grand
.ipc-sub-system summaryDetailed writeup coming later.. get your tickets at the boxoffice.
TLDR: this intros a
tractor.ipcsubpkg which begins our attempt atbeing IPC protocol agnostic from the perspective of all our
higher-level RPC APIs, namely:
ActorNursery.start_actor() -> Portal:Portal.open_context() -> Conext:Context.open_stream() -> MsgStream:That means including a new type-protocol
MsgTransportand (for nowgiven our lone
msgpackinterchange) a top-most implementationMsgpackTransportwhich contains,bulk of of the (original-prior) implementation for msg-IO over
a socket iface with, and as prior, the socket assumed to be already
wrapped-n-delivered ( for/by
trio) in atrio.abc.Stream.impls for each proto backend:
MsgpackUDSStream&MsgpackTCPStreama new
Addresstype-proto which equivalents allows conversionto/from each proto-specific (msgpack) wire-compat address-data-type
(normally some
tuple) with concrete impls to match:TCPAddress->tuple[str, int]UDSAddress->tuple[str, str]with what lands here you can toggle the global tpt proto with,
_state._def_tpt_proto: TransportProtocolKeyenable_transports: listtoopen_root_actor(), though right now we only support a singleentry until more testing is written Xp
Outstanding feat requests this relates-to/resolves
Still pending bugs and/or (minor) requirements
enable_transports=['uds']breaks subactor debugging XD._state._runtime_vars['_root_mailbox']passing to subactors_enable_tptsdown throughsubactors.
_root_addrsto the rtvars to get thesame semantic as the registry key, and implying that the root can
(eventually) be contacted on multiple addrs over varying
transports.
moved to #380
.ipc._serverprimitives
.ipc._servertypes naming/polishIdealistic todos before this lands
Gosh it'd sure be nice but I'd rather get UDS in sooner then later
sin unit-tests if it comes to it.
fix CI to use
uv(also see follow thru below)hopefully tweak wtv to get at least one run green..
typing-extensionsfortest_toolingaudit of our
stackscopeintegration.devx.debugsubpkg history) to get
.devx.test_toolingsuite green.factor out the
Actor._stream_handler()method to a mod-levelfunc either in
.ipc._serveror similar.also move over all the
Actor._peers: dict[tuple, Channel](and related state) tracking to the
IPCServerand change alldependent code to match.
Coming in follow-up patch(es)
see Improved
.__repr__()on all primitives #381 for pretty-format follow ups.see IPC subsys refinements: connection-tracking, multi-proto-endpoint-mgmt.. etc. #382 for follow-up on,
fill out the
IPCEndpoint.peer_tpttables (implicitly) by pre-hooking into anew (likely)
Endpoint(class) method which first registersevery
MsgTransport/Channelprior to processing and handover tothe RPC layer.
are on which transports and which
.stream_handler_tn: Nurserysso we can eventually do fancy stuff like connection resetting,
peer filtering, dynamic transport-proto swapping etc.
multiple-transports in tandem (eventually per actor) by first ensuring
the server layer is correct before exposing upward via
enable_transports: list[str]to runtime-bootingentrypoints (
open_nursery()/open_root_actor()).