Request cancellation
If a long-running task needs to be canceled upon a remote client closing the connection (e.g., closing a browser page), Volga supports tracking those scenarios by introducing a dedicated CancellationToken per HTTP request. Which is powered by Tokio's CancellationToken.
This is how it can be used:
use std::time::Duration;
use volga::{App, CancellationToken, ok};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new();
// Example of long-running task
app.map_get("/long-task", |cancellation_token: CancellationToken| async move {
// Running infinite loop until the remote client close the connection
let mut interval = tokio::time::interval(Duration::from_millis(1000));
while !cancellation_token.is_cancelled() {
interval.tick().await;
// Doing some long-running job...
}
ok!("done")
});
app.run().await
}
More robust version with using tokio::select!:
use std::time::Duration;
use volga::{App, CancellationToken, ok};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new();
// Example of long-running task
app.map_get("/long-task", |cancellation_token: CancellationToken| async move {
// Running infinite loop until the remote client close the connection
tokio::select! {
_ = cancellation_token.cancelled() => (),
result = long_running_task() => ()
}
ok!("done")
});
app.run().await
}
async fn long_running_task() {
let mut interval = tokio::time::interval(Duration::from_millis(100));
loop {
interval.tick().await;
// Doing some long-running job...
}
}
In the example above, when a remote client cancels the request, the cancellation_token.cancelled() will be finished first, and then tokio::select! will cancel the long_running_task().
This feature could help save a lot of computing resources, preventing long-running tasks from running for nothing, while fast, small tasks that run faster than 300 ms won't be affected.
When the Token Is Cancelled
A request's token belongs to its connection: it is cancelled when the connection fails — the client went away — and when a graceful shutdown runs out of time and closes the connection. A shutdown that has just started does not cancel it, since requests in flight are still answered; a handler that should wind down with the server takes a ShutdownHandle instead.
The handler is dropped along with its connection, so the token matters most for work that outlives the handler: a task it spawned, or a blocking body checking is_cancelled() as it goes. Cancelling the token from a handler notifies its clones and closes nothing.
Here you can find some additional information about CancellationToken.