pub struct Context { /* private fields */ }
Expand description
An object that is passed around to asynchronous functions that may be used to check if the function it was passed into should perform a graceful termination.
You build a new Context by calling its new
constructor, which returns the new Context
along with a Handle
. The Handle
can
either have its cancel
method called, or it can simply be dropped to
cancel the context.
Please note that dropping the Handle
will cancel the context.
If you would like to create a Context that automatically cancels after a given duration has
passed, use the with_timeout
constructor. Using this
constructor will still give you a handle that can be used to immediately cancel the context as
well.
§Examples
use tokio::time;
use tokio_context::context::Context;
use std::time::Duration;
async fn task_that_takes_too_long() {
time::sleep(time::Duration::from_secs(60)).await;
println!("done");
}
#[tokio::main]
async fn main() {
// We've decided that we want a long running asynchronous task to last for a maximum of 1
// second.
let (mut ctx, _handle) = Context::with_timeout(Duration::from_secs(1));
tokio::select! {
_ = ctx.done() => return,
_ = task_that_takes_too_long() => panic!("should never have gotten here"),
}
}
While this may look no different than simply using tokio::time::timeout
, we have retained a
handle that we can use to explicitly cancel the context, and any additionally spawned
contexts.
use std::time::Duration;
use tokio::time;
use tokio::task;
use tokio_context::context::Context;
async fn task_that_takes_too_long(mut ctx: Context) {
tokio::select! {
_ = ctx.done() => println!("cancelled early due to context"),
_ = time::sleep(time::Duration::from_secs(60)) => println!("done"),
}
}
#[tokio::main]
async fn main() {
let (_, mut handle) = Context::new();
let mut join_handles = vec![];
for i in 0..10 {
let mut ctx = handle.spawn_ctx();
let handle = task::spawn(async { task_that_takes_too_long(ctx).await });
join_handles.push(handle);
}
// Will cancel all spawned contexts.
handle.cancel();
// Now all join handles should gracefully close.
for join in join_handles {
join.await.unwrap();
}
}
The Context pattern is useful if your child future needs to know about the cancel signal. This is highly useful in many situations where a child future needs to perform graceful termination.
If you would like to use chainable contexts, see RefContext
.
In instances where graceful termination of child futures is not needed, the API provided by
TaskController
is much nicer to use. It doesn’t pollute children with
an extra function argument of the context. It will however perform abrupt future termination,
which may not always be desired.
Implementations§
Source§impl Context
impl Context
Sourcepub fn new() -> (Context, Handle)
pub fn new() -> (Context, Handle)
Builds a new Context without a timeout. The done
method returns a future that will
complete when this context is cancelled.
Sourcepub fn with_timeout(timeout: Duration) -> (Context, Handle)
pub fn with_timeout(timeout: Duration) -> (Context, Handle)
Builds a new Context. The done
method returns a future that will complete when
either the handle is cancelled, or when the supplied timeout has elapsed.
Sourcepub fn with_parent(
parent_ctx: &RefContext,
timeout: Option<Duration>,
) -> (Context, Handle)
pub fn with_parent( parent_ctx: &RefContext, timeout: Option<Duration>, ) -> (Context, Handle)
Builds a new Context, chained to a parent context. When done
is called off a chained
context it will return a future that will complete when either the handle is cancelled, the
optional timeout has elapsed, the parent context is cancelled, or the optional parent timeout
has elapsed.
Note that using this version means that the context chain will end here. If you want to
allow continuing the context chain, use RefContext::with_parent
.