design: usage stats in the model (BroadcastInfo-carried, origin-attributed)#1894
design: usage stats in the model (BroadcastInfo-carried, origin-attributed)#1894kixelated wants to merge 1 commit into
Conversation
Proposed architecture for per-broadcast usage stats, superseding the with_meter/set_meter approach on the stats-in-model branch (#1873). Sinks live in BroadcastInfo, set at construction; the immutable Arc<BroadcastInfo> carries them to every track/group/frame, which bump the atomics through a shared reference (no setter, no Arc::make_mut). The origin attributes egress per consuming session, and the model tracks live viewer/publisher counts. Tier and the published schema are intentionally left alone (the auth-root rework is a separate change). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| frames: AtomicU64, | ||
| bytes: AtomicU64, | ||
| // lifecycle, bumped as broadcast handles open/close (live = opened - closed) | ||
| opened: AtomicU64, |
There was a problem hiding this comment.
rename to active?
We only care about BroadcastConsumers that have at least one TrackConsumer instance open. Otherwise we're just counting the number of sessions where a broadcast is announced, which I guess is cool, but IDK.
How about announced: Gauge, and active: Gauge. Gauge is two atomics, open and closed.
| pub struct BroadcastInfo { | ||
| pub hops: OriginList, | ||
| pub epoch: SystemTime, | ||
| pub stats: BroadcastStats, |
There was a problem hiding this comment.
Maybe make this Arc instead of producer/consumer? So there's one item on the heap instead of two.
| The model owns "is this broadcast being watched / published," replacing | ||
| `SessionBroadcasts`: | ||
|
|
||
| - A `BroadcastConsumer` counts as **one live viewer while it has ≥ 1 outstanding |
There was a problem hiding this comment.
yeah some Arc that holds an Arc. when all TrackConsumers are dropped, the BroadcastActive is dropped and we update the Gauge. Maybe a bool on if it's a producer or consumer, or just make a separate type to avoid the branch IDK. Or have Arc like the plan suggests and ignore my previous comment.
|
|
||
| ## Out of scope (deliberately) | ||
|
|
||
| - **The `Tier` (internal/external) split.** It's kept as-is here. The intent |
There was a problem hiding this comment.
I think Origin should flag if a producer/consumer is internal/external? IDK there's something wrong with the Origin abstraction that needs to be untangled but I don't know how.
A design doc only — the proposed architecture for per-broadcast usage stats, to settle the shape before implementing. It supersedes the
with_meter/set_meterapproach currently on #1873.The idea
Put the usage sinks in
BroadcastInfo, set them at construction, and let the immutableArc<BroadcastInfo>carry them to every track/group/frame.Usageis atomics, so the model bumps through a shared&Arc<Usage>— no mutation, so nowith_metersetter and noArc::make_mut.OriginConsumer: when it hands out aBroadcastConsumerit builds that consumer's ownArc<BroadcastInfo>with this session's egress sink — so per-tier egress survives, with zero mutation, andwith_meterdisappears from every handler/gateway.BroadcastConsumeris one live viewer while it has ≥1 outstandingTrackConsumer. This replaces the stats-layerSessionBroadcastssentinel and fixes the fragile split where the payload sink came from a non-bumpingsubscriber_meter()while the lifecycle guard lived elsewhere.Arc<TrackInfo>is threaded to the group too, sotimescalestops being passed separately.Full writeup, type sketches, flows, and a 3-phase plan are in
rs/moq-net/DESIGN-stats.md.Deliberately out of scope
Tier(internal/external) split, and the published stats schema — both unchanged here. The intent behind tiers is real (billable customer traffic vs cluster forwarding), but encoding it as a fixed enum is rigid; moving attribution to per-auth-root keying is a cleaner model that reshapes the output format, so it's a separate change.Looking for a sign-off on the shape (especially construction-time attribution and the origin-injection hook) before I sink the ~1500-line implementation.
🤖 Generated with Claude Code
(Written by Claude)