Provides Tokio 1.46–1.50 and tokio-util 0.7.16–0.7.18 updates: SetOnce, JoinMap, JoinQueue, biased joins, cooperative scheduling, Notify::notified_owned. Use before Tokio async code.
npx claudepluginhub nevaberry/nevaberry-plugins --plugin tokio-knowledge-patchThis skill uses the workspace's default tool permissions.
Implements structured self-debugging workflow for AI agent failures: capture errors, diagnose patterns like loops or context overflow, apply contained recoveries, and generate introspection reports.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Covers Tokio 1.46–1.50 (Jul 2025 – Mar 2026) and tokio-util 0.7.16–0.7.18 (Aug 2025 – Jan 2026). Claude Opus 4.6 knows Tokio through 1.45 and tokio-util through 0.7.15.
| Topic | Reference | Key features |
|---|---|---|
| Task management | references/task-management.md | biased join, JoinSet::extend, JoinMap, JoinQueue |
| Synchronization | references/synchronization.md | SetOnce, Notify::notified_owned, CancellationToken adapters |
| Runtime & networking | references/runtime-and-networking.md | Cooperative scheduling APIs, is_rt_shutdown_err, set_zero_linger |
| API | Version | What it does |
|---|---|---|
join!(biased; ...) / try_join!(biased; ...) | 1.46 | Poll branches in declaration order |
sync::SetOnce | 1.47 | Async OnceLock — set once, await from many tasks |
Notify::notified_owned() | 1.47 | Returns OwnedNotified (no lifetime) for use in spawned tasks |
task::coop::poll_proceed(cx) | 1.47 | Cooperative yielding in custom Future/Stream impls |
task::coop::cooperative(fut) | 1.47 | Wrap async block to opt into coop scheduling |
JoinSet::extend(iter) | 1.49 | Collect futures directly into a JoinSet |
TcpStream::set_zero_linger(bool) | 1.49 | Replaces deprecated set_linger |
runtime::is_rt_shutdown_err(&e) | 1.50 | Check if error is caused by runtime shutdown |
| API | Version | What it does |
|---|---|---|
task::JoinMap<K, V> | 0.7.16 | Keyed JoinSet — associate a key with each spawned task |
task::JoinQueue | 0.7.17 | Like JoinSet but returns results in spawn (FIFO) order |
CancellationToken::unless_cancelled_with | 0.7.16 | Cancel futures directly with a token |
| Deprecated | Replacement | Version |
|---|---|---|
TcpStream::set_linger(Some(Duration::ZERO)) | TcpStream::set_zero_linger(true) | 1.49 |
TcpSocket::set_linger(Some(Duration::ZERO)) | TcpSocket::set_zero_linger(true) | 1.49 |
If you were calling set_linger(None) — just remove the call (OS default is no linger).
SetOnce — async one-time initializationuse tokio::sync::SetOnce;
static CONFIG: SetOnce<String> = SetOnce::const_new();
// First caller initializes; others wait then get the value
let val = CONFIG.get_or_init(|| async { load_config().await }).await;
// Non-blocking access after initialization
if let Some(cfg) = CONFIG.get() { /* already set */ }
JoinMap — keyed task setuse tokio_util::task::JoinMap;
let mut map = JoinMap::new();
map.spawn("fetch-users", async { fetch_users().await });
map.spawn("fetch-orders", async { fetch_orders().await });
while let Some((key, result)) = map.join_next().await {
println!("{key}: {result:?}");
}
JoinQueue — ordered task resultsuse tokio_util::task::JoinQueue;
let mut queue = JoinQueue::new();
queue.spawn(async { step_1().await });
queue.spawn(async { step_2().await });
// Results always in spawn order, regardless of completion order
while let Some(result) = queue.join_next().await {
process(result?);
}
join! — deterministic poll order// Polls in declaration order (like select!(biased; ...))
tokio::join!(biased; database_write, cache_invalidation, notification);
tokio::try_join!(biased; critical_op, secondary_op);
use tokio::task::coop;
// In a Stream::poll_next or Future::poll implementation:
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Item>> {
let coop = ready!(coop::poll_proceed(cx)); // yields if budget exhausted
let item = self.produce_item();
coop.made_progress();
Poll::Ready(Some(item))
}
match sender.send(msg).await {
Err(e) if tokio::runtime::is_rt_shutdown_err(&e) => {
// Runtime shutting down — clean exit
}
Err(e) => return Err(e.into()),
Ok(()) => {}
}
CancellationToken future adaptersuse tokio_util::sync::CancellationToken;
let token = CancellationToken::new();
let result = my_future.unless_cancelled_with(&token).await;
// Either::Left(value) on completion, Either::Right(()) on cancellation
JoinSet vs JoinMap vs JoinQueue — when to use which| Type | Crate | Result order | Keyed? | Use when |
|---|---|---|---|---|
JoinSet | tokio | Completion order | No | Fire-and-forget concurrent tasks |
JoinMap<K, V> | tokio-util | Completion order | Yes | Need to identify which task produced a result |
JoinQueue | tokio-util | Spawn (FIFO) order | No | Results must be processed in submission order |
All three support spawn, spawn_on, join_next, abort_all, len, and is_empty.
Notify lifetime guide| Method | Return type | Use when |
|---|---|---|
notify.notified() | Notified<'_> | Awaiting in the same scope |
notify.notified_owned() | OwnedNotified | Moving into tokio::spawn or storing in a struct |