https://github.com/milosgajdos/cancellation-patterns
Tokio task cancellation patterns
https://github.com/milosgajdos/cancellation-patterns
cancellation rust tokio tokio-rs
Last synced: about 2 months ago
JSON representation
Tokio task cancellation patterns
- Host: GitHub
- URL: https://github.com/milosgajdos/cancellation-patterns
- Owner: milosgajdos
- License: apache-2.0
- Created: 2024-04-19T08:42:51.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2024-04-19T15:46:43.000Z (about 1 year ago)
- Last Synced: 2025-02-03T11:51:01.246Z (4 months ago)
- Topics: cancellation, rust, tokio, tokio-rs
- Language: Rust
- Homepage:
- Size: 10.7 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# cancellation-patterns
Rust task cancellation patterns
[](https://github.com/milosgajdos/cancellation-patterns/actions?query=workflow%3ACI)
[](https://opensource.org/licenses/Apache-2.0)See the examples below or run them yourself. All the code is in [src](./src/bin)
# Aborting tasks
```rust
use tokio::time::{self, Duration};#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
// do some work
tokio::time::sleep(Duration::from_secs(1)).await;
println!("Task completed");
});// Cancel the task after 100 milliseconds
time::sleep(Duration::from_millis(100)).await;
handle.abort();
time::sleep(Duration::from_secs(2)).await;println!("Task was cancelled");
}
```# Oneshot channel
```rust
use tokio::time::Duration;
use tokio::{self, sync::oneshot};#[tokio::main]
async fn main() {
let (tx, rx) = oneshot::channel();let task = tokio::spawn(async move {
tokio::select! {
_ = rx => {
println!("Task is cancelling...");
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
println!("Task completed normally");
}
}
println!("Task is cleaning up");
});tokio::time::sleep(Duration::from_millis(100)).await;
// Send a cancellation signal
let _ = tx.send(());// Wait for the tasks to finish
// NOTE: we could do this instead:
// let _ = tokio::join!(task);
let _ = task.await;
}
```# Broadcast channel
```rust
use tokio::sync::broadcast;
use tokio::time::Duration;#[tokio::main]
async fn main() {
let (tx, mut rx1) = broadcast::channel(1);
let mut rx2 = tx.subscribe();let task1 = tokio::spawn(async move {
tokio::select! {
_ = rx1.recv() => {
println!("Task 1 is cancelling...");
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
println!("Task 1 completed normally");
}
}
println!("Task 1 is cleaning up");
});let task2 = tokio::spawn(async move {
tokio::select! {
_ = rx2.recv() => {
println!("Task 2 is cancelling...");
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
println!("Task 2 completed normally");
}
}
println!("Task 2 is cleaning up");
});tokio::time::sleep(Duration::from_millis(100)).await;
// Send a cancellation signal
let _ = tx.send(());// Wait for the tasks to finish
let _ = tokio::join!(task1, task2);
}
```# Watch channel
```rust
use tokio::sync::watch;
use tokio::time::Duration;#[tokio::main]
async fn main() {
let (tx, mut rx1) = watch::channel(false);
let mut rx2 = tx.subscribe();let task1 = tokio::spawn(async move {
loop {
tokio::select! {
_ = rx1.changed() => {
if *rx1.borrow() {
println!("Task 1 is cancelling...");
break;
}
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
println!("Task 1 completed normally");
break;
}
}
}
println!("Task 1 is cleaning up");
});let task2 = tokio::spawn(async move {
loop {
tokio::select! {
_ = rx2.changed() => {
if *rx2.borrow() {
println!("Task 2 is cancelling...");
break;
}
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
println!("Task 2 completed normally");
break;
}
}
}
println!("Task 2 is cleaning up");
});tokio::time::sleep(Duration::from_millis(100)).await;
// Send a cancellation signal
let _ = tx.send(true);// Wait for the tasks to finish
let _ = tokio::join!(task1, task2);
}
```# Cancellation token
```rust
use tokio::time::{sleep, Duration};
use tokio_util::sync::CancellationToken;#[tokio::main]
async fn main() {
// Create a CancellationToken
let token = CancellationToken::new();let token1 = token.clone();
let token2 = token.clone();let task1 = tokio::spawn(async move {
loop {
tokio::select! {
_ = token1.cancelled() => {
println!("Task 1 is cancelling...");
break;
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
println!("Task 1 completed normally");
break;
}
}
}
println!("Task 1 is cleaning up");
});let task2 = tokio::spawn(async move {
loop {
tokio::select! {
_ = token2.cancelled() => {
println!("Task 2 is cancelling...");
break;
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
println!("Task 2 completed normally");
break;
}
}
}
println!("Task 2 is cleaning up");
});sleep(Duration::from_millis(100)).await;
// Send a cancellation signal
token.cancel();// Wait for the tasks to finish
let _ = tokio::join!(task1, task2);
}
```