
Rust Async Patterns
Ship concurrent network services and async I/O in Rust with Tokio without guessing poll/waker semantics or error boundaries.
Overview
Rust Async Patterns is an agent skill for the Build phase that teaches Tokio-based async Rust—tasks, channels, streams, and error handling—for concurrent applications.
Install
npx skills add https://github.com/wshobson/agents --skill rust-async-patternsWhat is this skill?
- Covers Future poll model, Task spawning, and Runtime scheduling with Tokio
- Maps async-trait, anyhow, and tracing for production async stacks
- Documents concurrent patterns: channels, streams, and proper async error handling
- Targets debugging and performance tuning for stuck or pending futures
- Quick-start Cargo.toml for tokio full, futures, and tracing-subscriber
Adoption & trust: 13.5k installs on skills.sh; 36.5k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need async Rust that actually runs correctly under load but the poll/waker model and Tokio setup keep causing subtle bugs.
Who is it for?
Indie builders shipping Rust APIs, workers, or CLI tools that rely on Tokio and concurrent I/O.
Skip if: Teams that only need synchronous Rust scripts or frontends with no async backend.
When should I use this skill?
Building async Rust applications, implementing concurrent systems, or debugging async code with Tokio.
What do I get? / Deliverables
You get a consistent Tokio-oriented playbook for spawning tasks, handling async errors, and debugging futures so backend services compile and behave predictably.
- Tokio-oriented async module structure
- Error-handling and concurrency patterns applied to your crate
Recommended Skills
Journey fit
How it compares
Use as a structured async playbook instead of copying random Tokio snippets from forums.
Common Questions / FAQ
Who is rust-async-patterns for?
Solo and indie developers building async Rust services with Tokio who want production-oriented concurrency and error-handling patterns in one place.
When should I use rust-async-patterns?
During Build when implementing concurrent network handlers, wiring async traits, or debugging Pending futures before you ship perf-sensitive Rust.
Is rust-async-patterns safe to install?
Review the Security Audits panel on this Prism page and your org policy before installing any third-party agent skill.
SKILL.md
READMESKILL.md - Rust Async Patterns
# 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 ```toml # 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" ``` ```rust 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)) } ``` ## Patterns ### Pattern 1: Concurrent Task Execution ```rust use tokio::task::JoinSet; use anyhow::Result; // Spawn multiple concurrent tasks async fn fetch_all_concurrent(urls: Vec<String>) -> Result<Vec<String>> { let mut set = JoinSet::new(); for url in urls { set.spawn(async move { fetch_data(&url).await }); } let mut results = Vec::new(); while let Some(res) = set.join_next().await { match res { Ok(Ok(data)) => results.push(data), Ok(Err(e)) => tracing::error!("Task failed: {}", e), Err(e) => tracing::error!("Join error: {}", e), } } Ok(results) } // With concurrency limit use futures::stream::{self, StreamExt}; async fn fetch_with_limit(urls: Vec<String>, limit: usize) -> Vec<Result<String>> { stream::iter(urls) .map(|url| async move { fetch_data(&url).await }) .buffer_unordered(limit) // Max concurrent tasks .collect() .await } // Select first to complete use tokio::select; async fn race_requests(url1: &str, url2: &str) -> Result<String> { select! { result = fetch_data(url1) => result, result = fetch_data(url2) => result, } } ``` ### Pattern 2: Channels for Communication ```rust use tokio::sync::{mpsc, broadcast, oneshot, watch}; // Multi-producer, single-consumer async fn mpsc_example() { let (tx, mut rx) = mpsc::channel::<String>(100); // Spawn producer let tx2 = tx.clone(); tokio::spawn(async move { tx2.send("Hello".to_string()).await.unwrap(); }); // Consume while let Some(msg) = rx.recv().await { println!("Got: {}", msg); } } // Broadcast: multi-producer, multi-consumer async fn broadcast_example() { let (tx, _) = broadcast::channel::<String>(100); let mut rx1 = tx.subscribe(); let mut rx2 = tx.subscribe(); tx.send("Event".to_string()).unwrap(); // Both receivers get the message let _ = rx1.recv().await; let _ = rx2.recv().await; } // Oneshot: single value, single use async fn onesho