Skip to main content

Router

Struct Router 

Source
pub struct Router<W: Work, C: Clock = SystemClock, const CLASSES: usize = 2> { /* private fields */ }

Implementations§

Source§

impl<W, R, C, const CLASSES: usize> Router<Call<W, R>, C, CLASSES>
where W: Work, R: Send + 'static, C: Clock,

Source

pub async fn call(&self, work: W) -> Result<R, CallError<W>>

Submit and await the response, waiting on backpressure if the target shard’s mailbox is full.

Source

pub fn try_call(&self, work: W) -> Result<Answer<R>, SubmitError<W>>

Submit without waiting, reporting a full mailbox immediately and returning the response as a separate future.

Rejection is synchronous and the answer is not, which is exactly the shape a load-shedding caller needs: it can give up before committing to an await.

Source§

impl<W: Work, C: Clock, const CLASSES: usize> Router<W, C, CLASSES>

Source

pub fn new(shards: Vec<Mailbox<Envelope<W>>>, clock: C) -> Self

Source

pub fn with_options( shards: Vec<Mailbox<Envelope<W>>>, clock: C, stamp_arrival: bool, ) -> Self

stamp_arrival records a submission timestamp on every item, which powers queue-wait metrics and deadlines. Turning it off saves a clock read per submission: worth roughly a few percent of a core at millions of items per second: at the cost of both features.

Source

pub fn shards(&self) -> usize

Source

pub fn shard_index(&self, key: W::Key) -> usize

Which shard owns key. Stable for the lifetime of the router.

Source

pub async fn submit(&self, work: W) -> Result<(), SubmitError<W>>

Submit, waiting if the target shard’s mailbox is full.

That wait is the system’s backpressure: when a shard is saturated it stops admitting, its mailbox fills, and this call suspends the caller rather than growing an unbounded queue.

Source

pub fn try_submit(&self, work: W) -> Result<(), SubmitError<W>>

Submit without ever waiting, reporting a full mailbox instead.

Use this when shedding load is better than queueing it, which is often true under a latency objective.

Source

pub async fn submit_batch<I>(&self, work: I) -> Result<(), BatchError<W>>
where I: IntoIterator<Item = W>,

Submit many items, waiting on backpressure, and report everything that did not land.

Every item is attempted. One shard being unreachable does not stop items bound for the others, so a batch spanning shards is not held hostage by the worst of them.

The whole batch shares one arrival stamp. That is not an approximation: the caller held these items at one instant and handed them over at one instant, so that instant is when they arrived. Queue-wait is measured from it, and a deadline runs from it: including across a wait for mailbox space, because that wait is queueing, which is exactly what a deadline is meant to account for.

§Errors

BatchError carries every rejected item back with its reason, so a caller can answer, retry or shed each one. Items not named there were accepted.

Source

pub fn try_submit_batch<I>(&self, work: I) -> Result<(), BatchError<W>>
where I: IntoIterator<Item = W>,

Submit many items without ever waiting, reporting everything that did not land.

The shedding counterpart of submit_batch, and the one to reach for under a latency objective: a full mailbox rejects that item and the batch carries on rather than blocking behind it.

Auto Trait Implementations§

§

impl<W, C = SystemClock, const CLASSES: usize = 2> !RefUnwindSafe for Router<W, C, CLASSES>

§

impl<W, C = SystemClock, const CLASSES: usize = 2> !UnwindSafe for Router<W, C, CLASSES>

§

impl<W, C, const CLASSES: usize> Freeze for Router<W, C, CLASSES>
where Vec<Mailbox<Envelope<W>>>: Freeze, C: Freeze,

§

impl<W, C, const CLASSES: usize> Send for Router<W, C, CLASSES>
where Vec<Mailbox<Envelope<W>>>: Send,

§

impl<W, C, const CLASSES: usize> Sync for Router<W, C, CLASSES>
where Vec<Mailbox<Envelope<W>>>: Sync,

§

impl<W, C, const CLASSES: usize> Unpin for Router<W, C, CLASSES>
where Vec<Mailbox<Envelope<W>>>: Unpin, C: Unpin,

§

impl<W, C, const CLASSES: usize> UnsafeUnpin for Router<W, C, CLASSES>

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, 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, <T as TryFrom<U>>::Error>

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.