Add `d2` diagram sources + rendered SVGs
7 hand-authored `docs/diagrams/*.d2` sources (sketch-mode, grayscale theme, `elk` layout) w/ their pre-rendered fallback SVGs committed under `docs/_diagrams/` (served as-is when no `d2` bin is found, eg. in CI), - `actor_tree`: the hero supervision-tree, - `context_handshake`: seq diagram of the `Start`/`StartAck`/`Started`/`Yield`/`Stop`/`Return` ctx dialog, - `streaming_pipeline`: 4-actor fan-in topology, - `runtime_stack`: the per-actor layer cake, - `debug_lock`: root-tty-lock REPL serialization, - `error_propagation`: one-cancels-all boxed-err flow, - `infected_aio`: guest-mode loop nesting. Rendered w/ `d2` v0.7.1 via `nix run nixpkgs#d2`. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-codedocs_vibed_for_serious
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
|
@ -0,0 +1,31 @@
|
||||||
|
# tractor docs diagram: the hero supervision tree.
|
||||||
|
# A process tree of trio-task-trees; every arrow is
|
||||||
|
# a parent which *must wait* on its children.
|
||||||
|
vars: {
|
||||||
|
d2-config: {
|
||||||
|
sketch: true
|
||||||
|
theme-id: 1
|
||||||
|
pad: 16
|
||||||
|
layout-engine: elk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
direction: down
|
||||||
|
root: "root actor" {
|
||||||
|
main: "main()"
|
||||||
|
an: "ActorNursery"
|
||||||
|
main -> an: opens
|
||||||
|
}
|
||||||
|
w0: "subactor\n'worker_0'" {
|
||||||
|
tasks: "trio task tree"
|
||||||
|
}
|
||||||
|
w1: "subactor\n'worker_1'" {
|
||||||
|
main: "serve()"
|
||||||
|
an: "ActorNursery"
|
||||||
|
main -> an: opens
|
||||||
|
}
|
||||||
|
gc: "subactor\n'deeper'" {
|
||||||
|
tasks: "trio task tree"
|
||||||
|
}
|
||||||
|
root.an -> w0: "spawns +\nsupervises"
|
||||||
|
root.an -> w1: "spawns +\nsupervises"
|
||||||
|
w1.an -> gc: "spawns +\nsupervises"
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
# tractor docs diagram: the inter-actor `Context`
|
||||||
|
# dialog; tractor's SC-transitive msg protocol as
|
||||||
|
# seen from both sides of `Portal.open_context()`.
|
||||||
|
vars: {
|
||||||
|
d2-config: {
|
||||||
|
sketch: true
|
||||||
|
theme-id: 1
|
||||||
|
pad: 16
|
||||||
|
layout-engine: elk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shape: sequence_diagram
|
||||||
|
parent: "parent task\n(Portal)"
|
||||||
|
child: "child actor task\n(@tractor.context fn)"
|
||||||
|
parent -> child: "Start: open_context(fn, **kwargs)"
|
||||||
|
child -> parent: "StartAck"
|
||||||
|
child -> parent: "Started: await ctx.started(value)"
|
||||||
|
parent -> child: "Yield: stream.send()"
|
||||||
|
child -> parent: "Yield: stream.send()"
|
||||||
|
parent -> child: "Stop: stream closed"
|
||||||
|
child -> parent: "Return: fn return value"
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# tractor docs diagram: multi-actor debugger REPL
|
||||||
|
# serialization via the root actor's tty lock.
|
||||||
|
vars: {
|
||||||
|
d2-config: {
|
||||||
|
sketch: true
|
||||||
|
theme-id: 1
|
||||||
|
pad: 16
|
||||||
|
layout-engine: elk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shape: sequence_diagram
|
||||||
|
mary: "subactor 'mary'"
|
||||||
|
root: "root actor\n(owns the tty)"
|
||||||
|
bob: "subactor 'bob'"
|
||||||
|
mary -> root: "tractor.pause(): acquire tty lock"
|
||||||
|
root -> mary: "granted: pdb REPL is yours"
|
||||||
|
bob -> root: "tractor.pause(): acquire tty lock"
|
||||||
|
mary -> root: "continue: release lock"
|
||||||
|
root -> bob: "granted: pdb REPL is yours"
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
# tractor docs diagram: one-cancels-all error
|
||||||
|
# propagation up a (sub-)actor tree; no zombies,
|
||||||
|
# no lost errors.
|
||||||
|
vars: {
|
||||||
|
d2-config: {
|
||||||
|
sketch: true
|
||||||
|
theme-id: 1
|
||||||
|
pad: 16
|
||||||
|
layout-engine: elk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
direction: down
|
||||||
|
root: "root actor\n(ActorNursery)"
|
||||||
|
gertie: "subactor 'gertie'\n(healthy, gets cancelled)"
|
||||||
|
bobbie: "subactor 'bobbie'\nraises NameError"
|
||||||
|
root -> gertie: supervises
|
||||||
|
root -> bobbie: supervises
|
||||||
|
bobbie -> root: "RemoteActorError\n(boxed NameError)" {
|
||||||
|
style: {
|
||||||
|
stroke-dash: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root -> gertie: "cancel()" {
|
||||||
|
style: {
|
||||||
|
stroke-dash: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# tractor docs diagram: "infected asyncio" mode;
|
||||||
|
# trio runs as a guest on the asyncio loop with
|
||||||
|
# SC supervision linking tasks across both.
|
||||||
|
vars: {
|
||||||
|
d2-config: {
|
||||||
|
sketch: true
|
||||||
|
theme-id: 1
|
||||||
|
pad: 16
|
||||||
|
layout-engine: elk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
direction: down
|
||||||
|
sub: "subactor process (infect_asyncio=True)" {
|
||||||
|
aio: "asyncio event loop" {
|
||||||
|
aiotask: "asyncio.Task\naio_echo_server()"
|
||||||
|
trio: "trio (guest mode)" {
|
||||||
|
triotask: "trio task\n@tractor.context fn"
|
||||||
|
}
|
||||||
|
trio.triotask <-> aiotask: "LinkedTaskChannel\n.send()/.receive()"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent: "parent actor (pure trio)"
|
||||||
|
parent <-> sub.aio.trio.triotask: "IPC: Context + MsgStream"
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# tractor docs diagram: the layered runtime view
|
||||||
|
# inside any single actor process.
|
||||||
|
vars: {
|
||||||
|
d2-config: {
|
||||||
|
sketch: true
|
||||||
|
theme-id: 1
|
||||||
|
pad: 16
|
||||||
|
layout-engine: elk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grid-rows: 4
|
||||||
|
grid-gap: 0
|
||||||
|
app: "your app: plain trio tasks + nurseries"
|
||||||
|
tractor: "tractor runtime: actors, portals,\ncontexts + streams, RPC"
|
||||||
|
ipc: "IPC Channel: msgspec-typed msgs\nover TCP | UDS transports"
|
||||||
|
os: "OS: one process per actor"
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
# tractor docs diagram: multi-actor streaming
|
||||||
|
# pipeline topology from
|
||||||
|
# examples/full_fledged_streaming_service.py
|
||||||
|
vars: {
|
||||||
|
d2-config: {
|
||||||
|
sketch: true
|
||||||
|
theme-id: 1
|
||||||
|
pad: 16
|
||||||
|
layout-engine: elk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
direction: right
|
||||||
|
s0: "actor 'streamer_0'" {
|
||||||
|
fn: "stream_data(0)"
|
||||||
|
}
|
||||||
|
s1: "actor 'streamer_1'" {
|
||||||
|
fn: "stream_data(1)"
|
||||||
|
}
|
||||||
|
agg: "actor 'aggregator'" {
|
||||||
|
fn: "aggregate()"
|
||||||
|
}
|
||||||
|
main: "root actor" {
|
||||||
|
fn: "main()"
|
||||||
|
}
|
||||||
|
s0 -> agg: "async for:\nyielded ints"
|
||||||
|
s1 -> agg: "async for:\nyielded ints"
|
||||||
|
agg -> main: "deduped\nstream"
|
||||||