pub struct Exec { /* private fields */ }Expand description
A library’s whole surface onto the async runtime: tasks, timers and DNS.
An Exec is a Tokio handle and nothing more. It never owns the runtime,
so a task holding one can neither keep the runtime alive nor drop it from
inside itself. Cloning is a handle clone.
Why a type rather than plain tokio::spawn. A library that calls
tokio::spawn, tokio::time or tokio::net::lookup_host directly
demands that its caller be inside a Tokio reactor, on the very thread
that called it. Holding an Exec moves that requirement into the library:
the reactor is wherever the Exec points, the caller may drive the
returned futures on any executor — futures::executor::block_on
included — and a grep for those three names over the library’s own src
is the proof that no path escaped
(docs/ARCHITECTURE.md §5).
Implementations§
Source§impl Exec
impl Exec
Sourcepub fn from_handle(handle: Handle) -> Exec
pub fn from_handle(handle: Handle) -> Exec
Wraps the runtime handle names.
For a process that already runs a reactor somewhere other than the calling thread: nothing has to be ambient, and the caller’s own executor is never consulted.
Sourcepub fn current() -> Result<Exec, Error>
pub fn current() -> Result<Exec, Error>
The ambient handle.
Fails when the calling thread is not inside a Tokio runtime. Failing here — at construction — beats failing later at an unrelated call site.
Sourcepub fn owned(
worker_threads: usize,
thread_name: &str,
) -> Result<(Exec, OwnedReactor), Error>
pub fn owned( worker_threads: usize, thread_name: &str, ) -> Result<(Exec, OwnedReactor), Error>
Creates a multi-thread Tokio runtime with worker_threads workers,
named thread_name, and returns a handle onto it beside the
OwnedReactor that keeps it alive.
This is the constructor for a library whose users have no reactor at
all, which is most of a synchronous protocol library’s audience: the
library owns the reactor its sockets and timers need, and the caller
keeps its own executor — or none. The reactor dies with the returned
OwnedReactor, so a library holds it beside every handle it hands
out and drops it last.
Fails when worker_threads is 0, or when the OS refuses the
threads.
Sourcepub fn enter(&self) -> EnterGuard<'_>
pub fn enter(&self) -> EnterGuard<'_>
Enters the runtime context, for the constructors that register a
socket with the reactor as they are built — quinn’s endpoints,
tokio::net’s listeners. Held around the constructor only, never
across an await.
Sourcepub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output> ⓘ
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output> ⓘ
Spawns a task on the runtime. Works from any thread, with or without
an ambient reactor — which is why a library holding an Exec never
calls tokio::spawn.
Sourcepub fn sleep(&self, duration: Duration) -> Sleep ⓘ
pub fn sleep(&self, duration: Duration) -> Sleep ⓘ
A timer on this runtime’s wheel. The Sleep is created inside the
runtime context, so the returned future may be awaited anywhere.
Every clock a protocol has is one of these: a reconnect interval, a handshake deadline, a heartbeat, a connect timeout, a send or receive timeout, a linger budget.
Sourcepub async fn within<F: Future>(
&self,
limit: Duration,
future: F,
) -> Option<F::Output>
pub async fn within<F: Future>( &self, limit: Duration, future: F, ) -> Option<F::Output>
Awaits future, giving up after limit.
None means the future had not finished; it is dropped, so whatever
it held is released. This is the only place an await is bounded on
wall-clock time, for the same reason Exec::sleep lives here: the
timer belongs to the runtime, not to the caller.
Sourcepub async fn resolve(
&self,
host: &str,
port: u16,
max_addresses: usize,
) -> Result<Vec<SocketAddr>, Error>
pub async fn resolve( &self, host: &str, port: u16, max_addresses: usize, ) -> Result<Vec<SocketAddr>, Error>
Resolves host:port through the system resolver.
The convenience the competitor libraries use: a foreign-protocol client
dials what its own configuration names, and none of them has a reason
to let an application replace name resolution. weida’s own dial path
goes through crate::Resolver instead, because a weida://
authority may name a set and what a set means is the deployment’s
decision (docs/decisions/0020-cluster-and-discovery.md §4.2).
One implementation, two entry points: this delegates to
crate::SystemResolver.