rust-async
Skill0 starsChanged 8 months agoMITView on GitHub
Async Rust and concurrency with Tokio. Use when writing async code, choosing channel types (mpsc/broadcast/watch/oneshot), dealing with Send/Sync bounds, spawn_blocking, JoinSet, CancellationToken, or fixing issues with locks held across .await points. Also use for tokio::select!, graceful shutdown, and structured concurrency patterns.
4 other projects use a version of this.
Adopted by
Most recently taken up by
- lgzarturo/codeconductortheir own version, first seen Nov 1, 2026
- adxptived/Rust-Skillstheir own version, first seen Oct 17, 2026
- takurot/rust-skills-comprehensivetheir own version, first seen Oct 15, 2026
- huiali/rust-skillstheir own version, first seen Feb 9, 2026
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- huiali/rust-skills★ 47same name
- adxptived/Rust-Skills★ 1same name
- lgzarturo/codeconductor★ 0same name
- takurot/rust-skills-comprehensive★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository16 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- rust-apiSkill
- rust-architectureSkill
- rust-ci-deploySkill
- rust-databaseSkill
- rust-dddSkill
- rust-errorsSkill
- rust-macrosSkill
- rust-ownershipSkill
- rust-perfSkill
- rust-qualitySkill
- rust-serdeSkill
- rust-testsSkill
- rust-tracingSkill
- rust-typesSkill
- rust-unsafeSkill
The file
We split this skill into the rules it gives an agent
3 rules. 0 are common, 2 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 80
Never hold a std::sync::Mutex guard across an .await:
- Distinctive: line 94
Prefer restructuring to avoid holding locks across await entirely.
- Distinctive: line 104
Don't await them sequentially — that's 5x slower.
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Async & Concurrency
Core Question
Is this I/O-bound (async) or CPU-bound (threads/spawn_blocking)?
Async is for waiting on external things (network, disk,
timers). CPU-heavy work blocks the runtime — move it to
spawn_blocking or a dedicated thread pool.
Error → Design Question
| Symptom | Don't Just Say | Ask Instead |
Future is not Send | "Add Send bound" | Why does data cross a thread boundary? Can you restructure? |
| Deadlock with Mutex | "Use tokio::sync::Mutex" | Should you hold a lock across await at all? |
| Task hangs forever | "Add timeout" | Is there a cancellation path? |
| Channel fills up | "Make it unbounded" | What's the backpressure strategy? |
Quick Decisions
| Situation | Reach For | Why |
| Run independent futures concurrently | tokio::join! | Runs all, returns all results |
| Run fallible futures, fail fast | tokio::try_join! | Returns first error, drops rest |
| Race futures, handle first completion | tokio::select! | Cancel losers automatically |
| Dynamic number of spawned tasks | JoinSet | Add/remove tasks, collect results |
| CPU-intensive work in async context | spawn_blocking | Moves to blocking thread pool |
| File I/O in async code | tokio::fs | Non-blocking file operations |
| Graceful shutdown | CancellationToken | Hierarchical cancellation |
| One producer, one consumer, one message | oneshot | Request-response pattern |
| Work queue (multiple producers) | mpsc (bounded) | Backpressure built in |
| All subscribers get all messages | broadcast | Pub/sub pattern |
| Share latest value, skip intermediate | watch | Config updates, state sharing |
| Shared read-only data across tasks | Arc<T> | Clone Arc, not the data |
| Shared mutable state across tasks | Arc<Mutex<T>> | Or Arc<RwLock<T>> if reads dominate |
| Stream of async values | tokio_stream + StreamExt | Async equivalent of Iterator |
| Paginated API consumption | stream::unfold | Lazy, backpressure-aware page fetching |
| CPU-bound data parallelism | rayon::par_iter | Automatic work-stealing across cores |
| CPU-bound work in async context | spawn_blocking + rayon | Keep the async runtime unblocked |
| Scoped parallel work (no Arc) | std::thread::scope | Borrows stack data safely across threads |
| Atomic flag or counter | AtomicBool / AtomicUsize | Lock-free, single-word synchronization |
async fn in trait definition | native async fn in traits | No #[async_trait] needed since Rust 1.75 |
Channel Selection
| Channel | Pattern | Capacity | Receivers |
oneshot | Request → Response | 1 message | 1 |
mpsc | Work queue | Bounded (set capacity) | 1 |
broadcast | Pub/sub (all get all) | Bounded (ring buffer) | N (all messages) |
watch | Latest value | 1 (latest only) | N (skip to newest) |
Always use bounded channels unless you have a specific reason not to. Unbounded channels grow without limit when producer outpaces consumer.
Buffer sizing: start with num_producers * 2 or expected
burst size. Monitor with capacity() and len().
The Lock-Across-Await Problem
Never hold a std::sync::Mutex guard across an .await:
// Bad: guard held across await — can deadlock
let mut guard = data.lock().unwrap();
*guard = fetch().await;
// Good: extract, await, then lock again
let current = data.lock().unwrap().clone();
let new_data = process(current).await;
*data.lock().unwrap() = new_data;tokio::sync::Mutex is await-safe but has higher overhead.
Prefer restructuring to avoid holding locks across await
entirely.
Usage Scenarios
Scenario 1: "I need to make 5 HTTP requests and combine the results"
→ Use tokio::try_join! for a fixed number, or
JoinSet for a dynamic number.
Don't await them sequentially — that's 5x slower.
Scenario 2: "My async task needs to do JSON parsing on large payloads"
→ JSON parsing is CPU-bound. Use
spawn_blocking(move || serde_json::from_str(&data))
to avoid blocking the runtime.
Scenario 3: "I need to shut down gracefully when Ctrl+C is pressed"
→ Create a CancellationToken, pass child tokens to tasks,
and use tokio::select! to race work against
token.cancelled(). On signal, cancel the root token.
Reference Files
| File | Read When |
| references/tokio-patterns.md | Runtime setup, spawn_blocking, join/select patterns, JoinSet, cancellation |
| references/channels.md | Choosing and using mpsc/broadcast/watch/oneshot, backpressure, message patterns |
| references/safety.md | Lock safety across await, Send/Sync issues, clone-before-await patterns |
| references/streams.md | Stream trait, StreamExt, Pin, async fn in traits, paginated/WebSocket patterns |
| references/threads-and-parallelism.md | std::thread, rayon, crossbeam, atomics, async-vs-threads decision |
Cross-References
| When | Check |
| Smart pointers for shared state (Arc, Mutex) | rust-ownership → Quick Decisions |
| Error handling in async (try_join, ?) | rust-errors → Quick Decisions |
| Async trait design and Send bounds | rust-types → Quick Decisions |
| Tokio runtime profile settings | rust-perf → Quick Decisions |
| Tracing spans in async code, .instrument() | rust-tracing → Quick Decisions |
| Rayon, parallel iterators | rust-perf → Quick Decisions |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

