AudioProxy.VariantStore.Tee (audio_proxy v0.4.0)

Copy Markdown View Source

The write-back: a coordinator subscriber that streams a render into the variant store.

The render policy (CLAUDE.md) is to render at full speed into the write-back and let clients lag the render — which makes the tee not a special mechanism but simply one more subscriber to AudioProxy.RenderCoordinator's broadcast, one that consumes eagerly and writes through AudioProxy.VariantStore.put_stream/3. It never acknowledges anything (the coordinator releases the pipeline itself) and it never throttles anything (broadcast is a send, so a slow disk shows up as this process' mailbox, bounded by the coordinator's retention cap).

Because it is a subscriber, the disconnect policy changes exactly where the proposal says it does: with a store configured the tee keeps the subscriber count above zero after the last client leaves, so the render completes into the store and the next request is a HIT, where cache-off keeps today's cancel.

Ending

Three terminal outcomes, mirroring the coordinator's own:

  • {:done, …} — the chunk stream ends, put_stream/3 commits, the variant is readable.
  • {:error, …}, or the coordinator dying mid-render — the stream raises AudioProxy.VariantStore.Tee.Abort, put_stream/3 discards its staging, nothing is readable. Silent here: the render's own failure path has already told every client and the log.
  • The write failing under a healthy render — logged and instrumented via AudioProxy.Telemetry.store_write_failure/1, and invisible to clients, whose bytes flow from the coordinator and not from the store.

A mailbox deadline backstops all three, the same way the render action's does: a coordinator that stops saying anything at all cannot leave this process (and its staged temp file) behind forever. It restarts on every message and sits above AP_RENDER_TIMEOUT, so the pipeline's own timeout is what normally fires.

Started under AudioProxy.VariantStore.Tee.Supervisor — placed before the render tree in the application, so on shutdown the coordinators (which cancel their renders, aborting their tees) go first.

Summary

Functions

Starts a tee subscribed to render (a coordinator pid), writing key.

The task supervisor tees run under, for the application tree.

Functions

start(render, key, metadata)

@spec start(pid(), AudioProxy.VariantStore.key(), AudioProxy.VariantStore.metadata()) ::
  {:ok, pid()} | {:error, term()}

Starts a tee subscribed to render (a coordinator pid), writing key.

The caller — the coordinator itself, in init/1 — must register the returned pid as a subscriber before the first chunk is broadcast.

supervisor()

@spec supervisor() :: {module(), keyword()}

The task supervisor tees run under, for the application tree.