PluginBench
Skill
Pass
Audit score 90

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
Prerequisites
  • Rust toolchain installed
  • Basic understanding of Rust ownership and traits
  • Familiarity with async/await syntax
Claude Code
Cursor
Windsurf
Cline

How to use rust-async-patterns

  1. 1.Add tokio and dependencies to Cargo.toml with full features
  2. 2.Create async functions using async fn syntax
  3. 3.Use #[tokio::main] to initialize the runtime
  4. 4.Spawn concurrent tasks with tokio::spawn or JoinSet
  5. 5.Use tokio::select! to race multiple futures
  6. 6.Implement error handling with Result and ? operator
  7. 7.Add tracing instrumentation for debugging
  8. 8.Review references/details.md for advanced patterns

Use cases

Good for
  • 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
Who it's for
  • Rust backend developers
  • Systems programmers building concurrent services
  • DevOps engineers implementing async tooling
  • Anyone building production async Rust applications

rust-async-patterns FAQ

When should I use tokio::select! vs channels?

Use tokio::select! for racing futures and choosing the first to complete. Use channels for ongoing inter-task communication and decoupling producers from consumers.

Why can't I use std::thread::sleep in async code?

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.

How do I prevent deadlocks with async code?

Never hold locks (Mutex) across await points. If you need shared state, use channels or restructure to avoid holding locks during suspension.

What's the difference between Task and Future?

A Future is a lazy computation that must be polled. A Task is a spawned Future that the runtime actively polls concurrently.

How do I limit the number of concurrent tasks?

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

ConceptPurpose
FutureLazy computation that may complete later
async fnFunction returning impl Future
awaitSuspend until future completes
TaskSpawned future running concurrently
RuntimeExecutor 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::sleep in 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