Skip to main content

LivenessProbe

Struct LivenessProbe 

Source
pub struct LivenessProbe { /* private fields */ }
Expand description

The production driver of the liminal connection dead-man switch.

Shares the server’s shutdown watch, so it drains with the transports exactly like HeartbeatSweeper and the outbox dispatcher.

Implementations§

Source§

impl LivenessProbe

Source

pub fn new( notifier: Arc<LiminalConnectionNotifier>, tracker: HeartbeatTracker, registry: ConnectedWorkerRegistry, heartbeat_window: Duration, ) -> Self

Build a probe over the notifier that owns the liminal connections, the shared liveness tracker whose leases a pong refreshes, and the registry the WARN lines resolve a worker’s queue through.

Both timings derive from heartbeat_window (see the module docs); there is no separate configuration surface. This construction probes the LIMINAL transport only: it carries no gRPC answer-correlation registry, so it does not enumerate gRPC deliveries. Use Self::across_transports for the production probe.

Source

pub fn across_transports( notifier: Option<Arc<LiminalConnectionNotifier>>, grpc: Option<GrpcLivenessWaiters>, tracker: HeartbeatTracker, registry: ConnectedWorkerRegistry, heartbeat_window: Duration, ) -> Self

Build the probe that covers EVERY transport a worker may be delivered over (#197).

notifier is None on a boot with no liminal listener; grpc is the correlation registry the gRPC stream handler delivers answers into, and is None only for a probe that must not push gRPC pings it could never hear the answers to.

There is exactly ONE probe per server. Two would each publish a whole eligibility set over the other’s — the verdict is a replacement, not a merge — so the last writer would silently erase the other transport’s findings every cadence.

Source

pub const fn cadence(&self) -> Duration

The interval between probe rounds.

Source

pub const fn silence_window(&self) -> Duration

The silence window this probe declares to every worker it pings.

Source

pub async fn run(self, shutdown: Receiver<bool>)

Run the probe until shutdown flips to true.

Rounds never overlap: each tick’s pings are awaited to completion (each bounded by the cadence) before the next round starts, and a missed tick is skipped rather than queued.

That bounds the concurrent WAITS to one per connection. It was once claimed to bound the outstanding PUSHES to one as well, “so it can never crowd out real dispatches against liminal’s per-connection pending-push cap.” That claim was false and the failure it denied is exactly what happened on run dfd2117c: a push slot is not released by the caller giving up, only by a consumed reply, a deadline expiry, or a connection close. Awaiting a round to completion ends the wait, not the slot. So abandoning one unanswered no-deadline ping per round leaked one slot per round — 32 of them, then total refusal of every push on that connection.

The bound is now real because LiminalWorkerDelivery::push_payload_with_deadline attaches the cadence as the push’s own reply deadline, so an unanswered ping’s slot expires and RELEASES its cap admission instead of accumulating.

Source

pub async fn probe_once(&self, sequence: u64)

Ping every reachable worker once — liminal connections and gRPC task streams alike, concurrently — apply each answer to the worker’s dispatch probation, and publish ONE verdict for the round.

The two transports are pinged over their own wires, CONCURRENTLY with each other, and are otherwise indistinguishable from here down: the same probation, the same tracker, the same single Self::publish_reachability_verdict call.

EVERY round publishes, including one that found no target to ping. This module used to skip publication for an empty round, reasoning that “publishing an empty exclusion set would be indistinguishable from clearing one”. They are the same act, and skipping it is what left a stale verdict standing: a verdict is published by REPLACEMENT, so a round that publishes nothing leaves the previous round’s exclusions in force over a fleet this round measured afresh. The set is derived from the tracker’s standing evidence rather than from this round’s targets, so it is well defined whether or not anything was pinged (#25).

Public because it is the whole unit of work: Self::run is a timer around it and adds nothing but the schedule. Driving rounds directly is how a test states a probation in ROUNDS rather than in wall-clock sleeps, which is the difference between asserting the law and asserting this machine’s timing.

sequence must advance between rounds: it is the echo a worker’s answer is matched against, and repeating one would let a previous round’s late answer satisfy this round’s ping.

Trait Implementations§

Source§

impl Debug for LivenessProbe

Source§

fn fmt(&self, formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. 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> IntoMaybeUndefined<T> for T

Source§

fn into_maybe_undefined(self) -> MaybeUndefined<T>

Converts this value into a three-state builder argument.
Source§

impl<T> IntoOption<T> for T

Source§

fn into_option(self) -> Option<T>

Converts this value into an optional builder argument.
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

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

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
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