pub struct FanOut { /* private fields */ }Expand description
A publish in progress: a payload written once and fanned out to one stream per subscriber, without ever being held whole.
This is what Publisher::publish cannot do:
that call takes a Bytes and refuses anything above
Limits::subscriber_buffer_bytes, because a message that large could not
be enqueued for anybody. Here the chunk is what the budget bounds, so
the payload is unbounded and a 33 MB frame is an ordinary publish
(B-064, docs/requirements/zeughaus-video.md request 1).
The drop behaviour of GUARANTEES §6 is
per subscriber, not per publish. A subscriber whose budget or queue
cannot take a chunk loses this transfer — its stream is reset, so it
never mistakes a partial payload for a whole one — and it is counted in
Publisher::drops like any other fan-out drop.
Every other subscriber keeps receiving, and the publisher never waits for
the slowest one.
Dropping this handle without FanOut::finish aborts every copy, for the
same reason OutgoingTransfer resets on drop.
Implementations§
Source§impl FanOut
impl FanOut
Sourcepub fn subscribers(&self) -> usize
pub fn subscribers(&self) -> usize
Subscribers still receiving this transfer.
It only falls: a subscriber that loses a chunk is gone from this transfer, and one that subscribes while it is in flight receives the next message rather than half of this one.
Sourcepub async fn write_within(
&mut self,
chunk: impl Into<Bytes>,
limit: Duration,
) -> Result<usize, Error>
pub async fn write_within( &mut self, chunk: impl Into<Bytes>, limit: Duration, ) -> Result<usize, Error>
Writes the next chunk to every subscriber still receiving, waiting up
to limit for one that has no room, and returns how many subscribers
are left.
The bound is mandatory and finite, and it is the caller’s, for the
reason Runtime::drain takes one
(docs/decisions/0009-drain.md §4.4): waiting on a subscriber with no
deadline is how a publisher hangs on a peer’s behaviour, and refusing
to wait at all would make a payload larger than
Limits::subscriber_buffer_bytes impossible to send to anyone —
the publisher would outrun its own budget and abort every copy. A
subscriber that frees room inside limit keeps the transfer; one that
does not loses it, and only it.
One Bytes allocation is shared by every copy, so a chunk costs one
buffer regardless of subscriber count, and the payload is never held
whole anywhere.
Fails with Error::LimitExceeded for a chunk larger than
Limits::subscriber_buffer_bytes: such a chunk could never be
enqueued for anybody, and the point of this API is that the payload
need not fit while a chunk does.
Sourcepub fn write_now(&mut self, chunk: impl Into<Bytes>) -> Result<usize, Error>
pub fn write_now(&mut self, chunk: impl Into<Bytes>) -> Result<usize, Error>
Writes the next chunk without ever waiting: a subscriber with no room right now loses the transfer.
Fan-out’s Drop from GUARANTEES §6 in
its purest form, and the right call where a later chunk supersedes an
earlier one — a video frame, a market snapshot — because a subscriber
that cannot keep up should be waiting for the next transfer rather
than holding this one up. A publisher streaming a payload that must
arrive whole wants FanOut::write_within.
Sourcepub fn finish(self) -> usize
pub fn finish(self) -> usize
Ends the transfer, and returns how many subscribers received all of it as far as this side can tell.
“As far as this side can tell” is the honest claim: the count is the
subscribers whose every chunk was enqueued and whose FIN is queued
behind them. A fan-out copy carries no receipt — nobody holds a
Delivery for it — so the transport acknowledgement is awaited by the
drain and by nothing else (docs/decisions/0009-drain.md §4.2).