rust-async-patterns
wshobson/agents
Master Rust async programming with Tokio, async traits, error handling, and concurrent patterns.
What is rust-async-patterns?
Production patterns for async Rust programming with Tokio runtime, including tasks, channels, streams, and error handling. Use when building async Rust applications, implementing concurrent systems, or debugging async code.
- Understand Future execution model and async/await mechanics
- Implement concurrent tasks and task management with JoinSet
- Use channels and select! for inter-task communication
- Handle async errors properly with Result propagation
- Instrument async code with tracing for debugging
- Optimize async performance and avoid common pitfalls
How to install rust-async-patterns
npx skills add https://github.com/wshobson/agents --skill rust-async-patterns- Rust toolchain installed
- Basic understanding of Rust ownership and traits
- Familiarity with async/await syntax
How to use rust-async-patterns
- 1.Add tokio and dependencies to Cargo.toml with full features
- 2.Create async functions using async fn syntax
- 3.Use #[tokio::main] to initialize the runtime
- 4.Spawn concurrent tasks with tokio::spawn or JoinSet
- 5.Use tokio::select! to race multiple futures
- 6.Implement error handling with Result and ? operator
- 7.Add tracing instrumentation for debugging
- 8.Review references/details.md for advanced patterns
Use cases
- Building async network services with Tokio
- Implementing concurrent I/O operations and task coordination
- Debugging async code issues using tracing instrumentation
- Racing multiple futures with tokio::select!
- Managing multiple concurrent tasks with proper error handling
- Rust backend developers
- Systems programmers building concurrent services
- DevOps engineers implementing async tooling
- Anyone building production async Rust applications
rust-async-patterns FAQ
Use tokio::select! for racing futures and choosing the first to complete. Use channels for ongoing inter-task communication and decoupling producers from consumers.
std::thread::sleep blocks the entire thread, preventing the runtime from polling other futures. Use tokio::time::sleep instead, which yields control back to the runtime.
Never hold locks (Mutex) across await points. If you need shared state, use channels or restructure to avoid holding locks during suspension.
A Future is a lazy computation that must be polled. A Task is a spawned Future that the runtime actively polls concurrently.
Use a Semaphore to acquire permits before spawning tasks, or use JoinSet with bounded task limits to prevent unbounded spawning.
Full instructions (SKILL.md)
Source of truth, from wshobson/agents.
name: rust-async-patterns description: Master Rust async programming with Tokio, async traits, error handling, and concurrent patterns. Use when building async Rust applications, implementing concurrent systems, or debugging async code.
Rust Async Patterns
Production patterns for async Rust programming with Tokio runtime, including tasks, channels, streams, and error handling.
When to Use This Skill
- Building async Rust applications
- Implementing concurrent network services
- Using Tokio for async I/O
- Handling async errors properly
- Debugging async code issues
- Optimizing async performance
Core Concepts
1. Async Execution Model
Future (lazy) → poll() → Ready(value) | Pending
↑ ↓
Waker ← Runtime schedules
2. Key Abstractions
| Concept | Purpose |
|---|---|
Future | Lazy computation that may complete later |
async fn | Function returning impl Future |
await | Suspend until future completes |
Task | Spawned future running concurrently |
Runtime | Executor that polls futures |
Quick Start
# Cargo.toml
[dependencies]
tokio = { version = "1", features = ["full"] }
futures = "0.3"
async-trait = "0.1"
anyhow = "1.0"
tracing = "0.1"
tracing-subscriber = "0.3"
use tokio::time::{sleep, Duration};
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
// Initialize tracing
tracing_subscriber::fmt::init();
// Async operations
let result = fetch_data("https://api.example.com").await?;
println!("Got: {}", result);
Ok(())
}
async fn fetch_data(url: &str) -> Result<String> {
// Simulated async operation
sleep(Duration::from_millis(100)).await;
Ok(format!("Data from {}", url))
}
Detailed patterns and worked examples
Detailed pattern documentation lives in references/details.md. Read that file when the navigation tier above is insufficient.
Best Practices
Do's
- Use
tokio::select!- For racing futures - Prefer channels - Over shared state when possible
- Use
JoinSet- For managing multiple tasks - Instrument with tracing - For debugging async code
- Handle cancellation - Check
CancellationToken
Don'ts
- Don't block - Never use
std::thread::sleepin async - Don't hold locks across awaits - Causes deadlocks
- Don't spawn unboundedly - Use semaphores for limits
- Don't ignore errors - Propagate with
?or log - Don't forget Send bounds - For spawned futures
Related skills
More from wshobson/agents and the wider catalog.
tailwind-design-system
Build production-ready design systems with Tailwind CSS v4, design tokens, and component libraries.
typescript-advanced-types
Master TypeScript's advanced type system: generics, conditional types, mapped types, and utility types for type-safe applications.
nodejs-backend-patterns
Build production-ready Node.js backends with Express/Fastify, middleware patterns, auth, and database integration.
python-performance-optimization
Profile and optimize Python code using cProfile, memory profilers, and performance best practices.
brand-landingpage
Brand-first landing page designer with guided interviews and Stitch-powered iteration.
python-testing-patterns
Implement comprehensive testing strategies with pytest, fixtures, mocking, and test-driven development.