ComponentSpawner

Struct ComponentSpawner 

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

Component-scoped spawner for child tasks.

Every component in a topology consists of a primary task which runs the “core loop” of the component, and optionally a number of child tasks that range from handling network connections to processing compute-heavy work in a separate thread pool.

ComponentSpawner provides a component-scoped mechanism for spawning those child tasks under supervision. It is tied specifically to the dedicated per-component supervisor that each component gets, which ensures that child tasks spawned through this mechanism are properly attributed to the component, and also that their lifecycle is one-to-one with the component itself.

§Child lifecycle, and one-shot vs supervisable

We classify tasks as either one-shot or supervisable: one-shot tasks are those based on a provided closure, which cannot be reinitialized and so cannot be restarted, and supervisable tasks are those based on an implementation of Supervisable, which allows for (potentially) initializing the underlying task future multiple times.

One-shot tasks are always temporary, since they cannot be reinitialized. Supervisable tasks default to the same, and opt into being restarted via ChildBuilder::with_restart_type when the worker is built to be initialized more than once.

All child tasks default to being marked as non-significant, so their termination – clean or otherwise – leaves the component running. This is usually the correct behavior, but a component that cannot function without a particular child may wish to mark it significant, which stops the component when that child terminates.

See ChildBuilder::with_significant for more information.

§Interruptible vs non-interruptible

ComponentSpawner allows spawning two styles of child task: “interruptible” and “non-interruptible.” Interruptible tasks are wrapped such that when the supervisor signals shutdown, the shutdown signal is honored/polled despite whatever the logic is in the task itself does. Non-interruptible tasks still received a shutdown handle, but the task logic itself is responsible for honoring shutdown signals.

Non-interruptible tasks aren’t truly uninterrupible: following the normal behavior of async Rust and the behavior of futures, the future associated with a task can simply be no longer polled or dropped, effectively interrupting it when considered at the level of “will this task run to completion?”

§Worker pool

ComponentSpawner is topology-aware, which means callers have the ability to specify a child task runs on the shared “global” thread pool attached to a given topology. This should be used for compute-heavy tasks, which otherwise can affect the scheduling latency of I/O-heavy tasks.

§Task naming

Child task names should generally not contain unique patterns/tokens – such as monotonic IDs or high-cardinality values – as they are used for internal telemetry about the task. Generally, task names should be thought of as a category label: if a component spawns tasks for handling connections, it should prefer to name them like conn_handler instead of conn_handler_<ID or IP>.

A child task that must finish draining before the component stops:

spawner.spawn_noninterruptible("queue_drainer", |shutdown| drain(shutdown)).await?;

A compute-heavy task that belongs on the shared worker pool, which needs the builder to say so:

spawner.interruptible("encoder", encode()).on_worker_pool().spawn().await?;

Implementations§

Source§

impl ComponentSpawner

Source

pub fn new(handle: SupervisorHandle, worker_pool: Handle) -> Self

Creates a new ComponentSpawner.

worker_pool is the shared worker pool owned by the topology, used by children that opt in via ChildBuilder::on_worker_pool.

The supervisor behind handle MUST carry a shutdown budget (Supervisor::with_shutdown_budget). Children spawned here have no deadline of their own, so without one a child that ignores shutdown stalls the drain indefinitely.

Source

pub fn interruptible<N, Fut>(&self, name: N, fut: Fut) -> ChildBuilder<'_>
where N: Into<String>, Fut: Future + Send + 'static, Fut::Output: IntoWorkerResult,

Creates a builder for an interruptible child task.

Interruptible tasks are implicitly wrapped such that shutdown is polled alongside the underlying task future, ensuring that shutdown is observed at the earliest possible moment. They are best used for work which has no requirements on orderly shutdown, draining of remaining work, and so on.

Use this method when advanced configuration of the underlying task is required. Otherwise, prefer spawn_interruptible.

Source

pub fn noninterruptible<N, F, Fut>(&self, name: N, f: F) -> ChildBuilder<'_>
where N: Into<String>, F: FnOnce(ShutdownHandle) -> Fut + Send + 'static, Fut: Future + Send + 'static, Fut::Output: IntoWorkerResult,

Creates a builder for a non-interruptible child task.

Non-interruptible tasks are those which handle shutdown signals directly in order to precisely control when the task completes. They are best used for tasks which must perform some operation, or operations, between the receiving of a shutdown signal and completion.

Non-interruptible tasks are not necessarily blocking: running a non-interruptible does not mean that it is guaranteed to complete, only that it won’t be wrapped in a way that tries to shutdown at the earliest possible moment.

Use this method when advanced configuration of the underlying task is required. Otherwise, prefer spawn_noninterruptible.

Source

pub fn supervisable<T>(&self, worker: T) -> ChildBuilder<'_, Restartable>
where T: Supervisable + 'static,

Creates a builder for a supervisable child task.

Supervisable tasks are those where the worker already implements Supervisable, which lets ComponentSpawner serve as a consistent control surface for spawning both arbitrary asynchronous functions and more full-fledged workers.

Supervisable tasks are set to permanently restart by default.

Use this method when advanced configuration of the underlying task is required. Otherwise, prefer spawn_supervisable.

Source

pub async fn spawn_interruptible<N, Fut>( &self, name: N, fut: Fut, ) -> Result<ChildId, SpawnError>
where N: Into<String>, Fut: Future + Send + 'static, Fut::Output: IntoWorkerResult,

Spawns an interruptible child task.

Interruptible tasks are implicitly wrapped such that shutdown is polled alongside the underlying task future, ensuring that shutdown is observed at the earliest possible moment. They are best used for work which has no requirements on orderly shutdown, draining of remaining work, and so on.

Use interruptible when advanced configuration of the underlying task is required.

§Errors

If the component’s supervisor isn’t running, or the child specification is invalid, an error is returned.

Source

pub async fn spawn_noninterruptible<N, F, Fut>( &self, name: N, f: F, ) -> Result<ChildId, SpawnError>
where N: Into<String>, F: FnOnce(ShutdownHandle) -> Fut + Send + 'static, Fut: Future + Send + 'static, Fut::Output: IntoWorkerResult,

Spawns a non-interruptible child task.

Non-interruptible tasks are those which handle shutdown signals directly in order to precisely control when the task completes. They are best used for tasks which must perform some operation, or operations, between the receiving of a shutdown signal and completion.

Non-interruptible tasks are not necessarily blocking: running a non-interruptible does not mean that it is guaranteed to complete, only that it won’t be wrapped in a way that tries to shutdown at the earliest possible moment.

Use noninterruptible when advanced configuration of the underlying task is required.

§Errors

If the component’s supervisor isn’t running, or the child specification is invalid, an error is returned.

Source

pub async fn spawn_supervisable<T>( &self, worker: T, ) -> Result<ChildId, SpawnError>
where T: Supervisable + 'static,

Spawns a supervisable child task.

Supervisable tasks are those where the worker already implements Supervisable, which lets ComponentSpawner serve as a consistent control surface for spawning both arbitrary asynchronous functions and more full-fledged workers.

Use supervisable when advanced configuration of the underlying task is required.

§Errors

If the component’s supervisor isn’t running, or the child specification is invalid, an error is returned.

Source

pub fn worker_pool(&self) -> &Handle

Returns a handle to the shared worker pool owned by the topology.

Source

pub fn handle(&self) -> &SupervisorHandle

Returns the underlying supervisor handle.

Source

pub fn active_children(&self) -> usize

Returns the number of children currently running that were spawned through a spawner.

Statically registered children – the component itself, in a topology – are not counted.

Trait Implementations§

Source§

impl Clone for ComponentSpawner

Source§

fn clone(&self) -> ComponentSpawner

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. 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<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
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> 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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
§

impl<T> Track for T

§

fn track_resources(self, token: ResourceGroupToken) -> Tracked<Self>

Instruments this type by attaching the given resource group token, returning a Tracked wrapper. Read more
§

fn in_current_resource_group(self) -> Tracked<Self>

Instruments this type by attaching the current resource group, returning a Tracked wrapper. Read more
Source§

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

Source§

type Error = Infallible

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.
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
Source§

impl<T> CloneAny for T
where T: Any + Clone,