Push a frame instead of storing and fetching it
The rate the media dtypes could carry was one frame every second or two: each
was a file on the data volume, an event on the socket, and a request back for
the bytes. This closes both halves of that, and they are one feature.
`save_artifact(..., volatile=True)` writes to a `VolatileStore` — the same
content-addressed store, in `/dev/shm`, bounded by size with the oldest falling
out (`ARTIFACT_VOLATILE_BYTES`, 48 MB under the container's raised `shm_size`).
Nothing sweeps it: a frame nobody kept is not worth walking the store to find.
`ArtifactStore.path` falls through to it, which is what lets a volatile frame be
an ordinary reference everywhere else — the dtype check, a panel's digest scope,
`load_artifact` in a node, and the widget's own fetch all work on one unchanged.
`adopt` copies one into the store when a run records it, so "returned media is
kept, emitted media is not" stays true.
The bytes then go down the flows websocket as a length-prefixed binary frame,
sent just ahead of the `message_value` naming them, so a tile has the frame when
it hears the value moved. Nothing is pushed unasked: a client names the messages
it is drawing (`{"type":"media","names":[…]}`), a panel's list is intersected
with the scope it already had, and only the newest frame per name in a batch is
sent — a client that fell behind is not handed frames it would draw over. The
tunnel relays text only, so a screen reached through a portal falls back to
fetching, which is why the rate table now has two rows.
Around the edges: the remote worker's fetch cache is bounded at last
(`FLUKSIO_ARTIFACT_CACHE_BYTES`), since content addressing means nothing in it
ever expires and a media stream fills it with chunks nothing asks for twice; a
port carrying an image draws the frame in the node panel rather than only
saying `image/png · frame.png · 1.79kB`; and an edge chip says that much instead
of a line of hash. The media screenshot stops waiting for `networkidle` — a
camera is a socket that never goes quiet, which is the point of it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YC4u66vjzW54fnHu5Juhh9
This commit is contained in:
@@ -131,6 +131,9 @@ warning into a refusal to start.
|
||||
| `OBS_RETENTION_DAYS` | `30` | how long metrics, events and run records are kept |
|
||||
| `ARTIFACT_GC_INTERVAL_S` | `3600` | how often artifact bytes nothing refers to are swept away; 0 never sweeps |
|
||||
| `ARTIFACT_GC_GRACE_S` | `3600` | how long a freshly written artifact is spared, whatever refers to it |
|
||||
| `MAX_ARTIFACT_BYTES` | `2147483648` | the largest body `PUT /artifacts` will take; 0 removes the limit |
|
||||
| `ARTIFACT_VOLATILE_DIR` | worked out | where frames a flow only shows live are held; empty picks a directory under `/dev/shm` named for the data directory, and falls back to the temporary directory |
|
||||
| `ARTIFACT_VOLATILE_BYTES` | `50331648` | how much that ring holds before the oldest frames fall out; 0 turns it off and volatile saves land in the store |
|
||||
|
||||
The three concurrency limits are also flags on `fluksio serve`
|
||||
(`--max-workers`, `--max-cascades`, `--max-runs`), as is the card count,
|
||||
@@ -146,6 +149,15 @@ sweep is what keeps a flow streaming media from filling the disk. It stands
|
||||
aside entirely while a run is in flight, since a node may store a checkpoint
|
||||
long before it returns the reference to it.
|
||||
|
||||
Frames saved with `volatile=True` skip all of that. They go to a ring in memory
|
||||
instead of the volume, the oldest falling out once the newest need the room,
|
||||
and the engine pushes them down the websocket to whichever screens are drawing
|
||||
them — which is what a camera at ten frames a second needs and the store cannot
|
||||
give it. A frame a run *records* is copied into the store on the way, so
|
||||
returned media is kept and emitted media is not. Under Docker the ring lives in
|
||||
the container's `/dev/shm`, whose default is 64 MB: raise `shm_size` alongside
|
||||
`ARTIFACT_VOLATILE_BYTES`.
|
||||
|
||||
A node that declares nothing is not accounted against `FLOW_CPUS`; it runs on
|
||||
the shared pool and is given `FLOW_CPUS / FLOW_MAX_WORKERS` as a thread cap, so
|
||||
several at once cannot each size themselves to the whole machine. Setting
|
||||
|
||||
Reference in New Issue
Block a user