Skip to main content

FanOut

Struct FanOut 

Source
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

Source

pub fn topic(&self) -> &str

The topic this transfer is published on.

Source

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.

Source

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.

Source

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.

Source

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).

Trait Implementations§

Source§

impl Drop for FanOut

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more