mcpField
R
rust-async-task-design

rust-async-task-design

github.com/lvtd-llcDevelopment161 installsUpdated 8w ago
Repository

About rust-async-task-design

A Rust coding skill for designing and reviewing async task behavior, including ownership, suspension, blocking work, and cancellation. It gives developers a workflow and review checklist for making concurrency decisions explicit.

Key features

  1. 01Trace suspension points and held state
  2. 02Manage spawned task ownership and handles
  3. 03Isolate blocking and CPU-heavy work
  4. 04Review locks and borrows across await
  5. 05Check cancellation and failure paths

Use cases

  1. 01Reviewing Tokio task spawning
  2. 02Finding locks held across await
  3. 03Separating blocking work from async tasks
  4. 04Testing timeout and cancellation behavior

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/lvtd-llc/skills --skill rust-async-task-design

After installing, type/rust-async-task-designin Claude Code to confirm it loaded.

Bundled filesagents/openai.yamlreferences/async-runtime-patterns.md

Details

From the project README

Rust Async Task Design

Use this skill to make Rust async code explicit about task ownership, suspension points, blocking work, and cancellation. Async is a concurrency model, not a default replacement for threads or a performance guarantee.

Core Workflow

  1. Identify the async boundary: runtime entrypoint, handler, client call, stream, background task, or trait method.
  2. Mark every .await as a possible suspension point. Check what state is held across it.
  3. Use tokio::spawn(async move { ... }) only when the task can own everything it needs and its future is Send + 'static on the selected runtime.
  4. Keep JoinHandles when task success, panic, cancellation, or shutdown matters. Do not silently detach important work.
  5. Keep blocking IO and CPU-heavy work out of async tasks. Use async APIs, spawn_blocking, Rayon, or dedicated threads as the workload requires.
  6. Do not hold a synchronous MutexGuard, RefCell borrow, or non-Send value across .await.
  7. Add tests for timeout, cancellation, dropped channel, and failed task paths when those outcomes affect behavior.

Runtime Rules

Read references/async-runtime-patterns.md when reviewing task spawning, shared state in async code, or blocking work.

  • Use std::sync::Mutex in async code only for short, low-contention critical sections that do not cross .await.
  • Use tokio::sync::Mutex when a lock must be held across .await, but first consider moving the state behind a task and interacting by messages.
  • Use spawn_blocking for blocking operations that eventually finish. Limit parallelism for CPU-heavy work; Tokio's blocking pool can grow large.
  • Use tokio::time::timeout or explicit cancellation tokens for bounded operations.
  • Use select! carefully: dropping a future can cancel it. Check cancellation safety before using it around IO or partially completed work.

Async Trait Rules

  • Native async fn in traits is fine for private traits and static dispatch when callers do not need to add bounds to the returned future.
  • Public traits that need Send futures should usually spell the method as fn name(...) -> impl Future<Output = T> + Send or use trait-variant to offer local and Send variants.
  • Public traits that need dynamic dispatch usually need an explicit boxed future return type, such as Pin<Box<dyn Future<Output = T> + Send + '_>>. Use async-trait as an ergonomics layer only when the dependency and allocation tradeoff are acceptable.
  • Avoid leaking executor-specific types from a trait unless the trait is intentionally runtime-specific.

Review Checklist

  • No lock or borrow crosses .await accidentally.
  • Spawned tasks own their inputs with async move.
  • Important JoinHandles are awaited, monitored, or aborted on shutdown.
  • Blocking work is isolated and bounded.
  • Error paths preserve context instead of becoming JoinError or timeout noise.

Comments

Markdown supported