pub struct WorkerArrival { /* private fields */ }Expand description
A live subscription to the next change in what dispatch selection can see,
taken from ConnectedWorkerRegistry::worker_arrival and awaited as a
future.
§Why this is a value and not a bare wait method
The registry’s two wake sources — a registration
(ConnectedWorkerRegistry::register and every sibling, through their
shared tail) and a published reachability verdict
(ConnectedWorkerRegistry::set_dispatch_ineligible) — are both
Notify::notify_waiters, which stores no permit. A caller that reads the
registry, misses, and only then constructs its wait has already lost any
arrival that landed during the read: the broadcast fired into an empty waiter
list. That caller then sleeps on a pool it holds positive evidence is served,
until some unrelated later registration happens to wake it — and on the gRPC
transport, where no liveness probe runs and no verdict is ever published, an
unrelated registration is the ONLY thing that ever could.
So the subscription is a value the caller takes before it looks, and awaits after it has missed. Everything that fires in between is retained.
§Why it is retained — tokio 1.52.3 at the bytes
Line numbers are in tokio-1.52.3/src/sync/notify.rs, the version
Cargo.lock pins.
Notify::notified_owned(:613) snapshots the process-widenotify_waiterscall counter into the future at construction (:619,notify_waiters_calls: get_num_notify_waiters_calls(state)).notify_waiters(:743) increments that counter unconditionally —inner_notify_waitersbumps it at:755when nobody is parked and at:761when someone is. A broadcast into an empty list is therefore not lost; it moves a number.poll_notified’sState::Initarm compares the snapshot against the live counter at:1124, and again under the waiter lock at:1156; a difference sends the future straight toState::Done→Poll::Ready.
That comparison is the retention property, and it belongs to construction.
OwnedNotified::enable (:1059) is called here too: it runs that same Init
arm eagerly and, on the not-yet-notified path, pushes the waiter into the list
at :1219 — so the waiter is registered at a defined point rather than at
first poll, and a notify_one permit would be retained as well if one were
ever added to this Notify. There is none today; this type must not rest its
correctness on that staying true.
§What it costs
OwnedNotified rather than the borrowed Notified<'_> because the value
crosses a &mut dyn FnMut(..) boundary (the wait path’s park contract) and
sits in a tokio::select! arm (the bridge’s park); the borrowed form forces
a higher-ranked bound through the first and pinning ceremony at the second.
Pin<Box<_>> because enable needs Pin<&mut Self> at construction, and
because it makes this type Unpin so no call site owes pinning ceremony. The
price is one heap allocation per selection-loop iteration, on a path that is
about to park. The alternative — hand back a bare OwnedNotified and ask
every call site to remember pin! and enable() — puts the obligation back
on the call sites, and a call site that forgot its obligation is precisely
the defect this type exists to end.
Trait Implementations§
Source§impl Debug for WorkerArrival
impl Debug for WorkerArrival
Source§impl Future for WorkerArrival
impl Future for WorkerArrival
Auto Trait Implementations§
impl !RefUnwindSafe for WorkerArrival
impl !UnwindSafe for WorkerArrival
impl Freeze for WorkerArrival
impl Send for WorkerArrival
impl Sync for WorkerArrival
impl Unpin for WorkerArrival
impl UnsafeUnpin for WorkerArrival
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn map<U, F>(self, f: F) -> Map<Self, F> ⓘ
fn map<U, F>(self, f: F) -> Map<Self, F> ⓘ
Source§fn map_into<U>(self) -> MapInto<Self, U> ⓘ
fn map_into<U>(self) -> MapInto<Self, U> ⓘ
Source§fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F> ⓘ
fn then<Fut, F>(self, f: F) -> Then<Self, Fut, F> ⓘ
f. Read moreSource§fn left_future<B>(self) -> Either<Self, B> ⓘ
fn left_future<B>(self) -> Either<Self, B> ⓘ
Source§fn right_future<A>(self) -> Either<A, Self> ⓘ
fn right_future<A>(self) -> Either<A, Self> ⓘ
Source§fn into_stream(self) -> IntoStream<Self>where
Self: Sized,
fn into_stream(self) -> IntoStream<Self>where
Self: Sized,
Source§fn flatten(self) -> Flatten<Self> ⓘ
fn flatten(self) -> Flatten<Self> ⓘ
Source§fn flatten_stream(self) -> FlattenStream<Self>
fn flatten_stream(self) -> FlattenStream<Self>
Source§fn fuse(self) -> Fuse<Self> ⓘwhere
Self: Sized,
fn fuse(self) -> Fuse<Self> ⓘwhere
Self: Sized,
poll will never again be called once it has
completed. This method can be used to turn any Future into a
FusedFuture. Read moreSource§fn inspect<F>(self, f: F) -> Inspect<Self, F> ⓘ
fn inspect<F>(self, f: F) -> Inspect<Self, F> ⓘ
Source§fn catch_unwind(self) -> CatchUnwind<Self> ⓘwhere
Self: Sized + UnwindSafe,
fn catch_unwind(self) -> CatchUnwind<Self> ⓘwhere
Self: Sized + UnwindSafe,
Source§fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)where
Self: Sized,
fn remote_handle(self) -> (Remote<Self>, RemoteHandle<Self::Output>)where
Self: Sized,
() on completion and sends
its output to another future on a separate task. Read moreSource§fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
fn boxed<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>
Source§fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>where
Self: Sized + 'a,
fn boxed_local<'a>(self) -> Pin<Box<dyn Future<Output = Self::Output> + 'a>>where
Self: Sized + 'a,
Source§fn unit_error(self) -> UnitError<Self> ⓘwhere
Self: Sized,
fn unit_error(self) -> UnitError<Self> ⓘwhere
Self: Sized,
Future<Output = T> into a
TryFuture<Ok = T, Error = ()>.Source§fn never_error(self) -> NeverError<Self> ⓘwhere
Self: Sized,
fn never_error(self) -> NeverError<Self> ⓘwhere
Self: Sized,
Future<Output = T> into a
TryFuture<Ok = T, Error = Never>.Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_cancellation_token(
self,
cancellation_token: &CancellationToken,
) -> WithCancellationTokenFuture<'_, Self>where
Self: Sized,
fn with_cancellation_token(
self,
cancellation_token: &CancellationToken,
) -> WithCancellationTokenFuture<'_, Self>where
Self: Sized,
CancellationToken::run_until_cancelled,
but with the advantage that it is easier to write fluent call chains. Read moreSource§fn with_cancellation_token_owned(
self,
cancellation_token: CancellationToken,
) -> WithCancellationTokenFutureOwned<Self>where
Self: Sized,
fn with_cancellation_token_owned(
self,
cancellation_token: CancellationToken,
) -> WithCancellationTokenFutureOwned<Self>where
Self: Sized,
CancellationToken::run_until_cancelled_owned,
but with the advantage that it is easier to write fluent call chains. Read moreSource§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<F> IntoFuture for Fwhere
F: Future,
impl<F> IntoFuture for Fwhere
F: Future,
Source§type IntoFuture = F
type IntoFuture = F
Source§fn into_future(self) -> <F as IntoFuture>::IntoFuture
fn into_future(self) -> <F as IntoFuture>::IntoFuture
Source§impl<T> IntoMaybeUndefined<T> for T
impl<T> IntoMaybeUndefined<T> for T
Source§fn into_maybe_undefined(self) -> MaybeUndefined<T>
fn into_maybe_undefined(self) -> MaybeUndefined<T>
Source§impl<T> IntoOption<T> for T
impl<T> IntoOption<T> for T
Source§fn into_option(self) -> Option<T>
fn into_option(self) -> Option<T>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request