| name | tokio-async-code-review |
| description | Reviews tokio async runtime usage for task management, sync primitives, channel patterns, and runtime configuration. Use when reviewing Rust code that uses tokio, async/await patterns, spawn, channels, or async synchronization. Also covers tokio-util, tower, and hyper integration patterns. |
Tokio Async Code Review
Review Workflow
- Check Cargo.toml — Note tokio feature flags (
full, rt-multi-thread, macros, sync, etc.). Missing features cause confusing compile errors.
- Check runtime setup — Is
#[tokio::main] or manual runtime construction used? Multi-thread vs current-thread?
- Scan for blocking — Search for
std::fs, std::net, std::thread::sleep, CPU-heavy loops in async functions.
- Check channel usage — Match channel type to communication pattern (mpsc, broadcast, oneshot, watch).
- Check sync primitives — Verify correct mutex type, proper guard lifetimes, no deadlock potential.
Output Format
Report findings as:
[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.
Quick Reference
Review Checklist
Runtime Configuration
Task Management
Sync Primitives
Channels
Timer and Sleep
Severity Calibration
Critical
- Blocking I/O (
std::fs::read, std::net::TcpStream) in async context without spawn_blocking
- Mutex guard held across
.await point (deadlock potential)
std::thread::sleep in async function (blocks runtime thread)
- Unbounded channel where back-pressure is needed (OOM risk)
Major
JoinHandle silently dropped (lost errors, zombie tasks)
- Missing
select! cancellation safety consideration
- Wrong mutex type (std vs tokio) for the use case
- Missing timeout on network/external operations
Minor
tokio::spawn for trivially small async blocks (overhead > benefit)
- Overly large channel buffer without justification
- Manual runtime construction where
#[tokio::main] suffices
std::sync::Mutex where contention is high enough to benefit from tokio's async mutex
Informational
- Suggestions to use
tokio-util utilities (e.g., CancellationToken)
- Tower middleware patterns for service composition
- Structured concurrency with
JoinSet
Valid Patterns (Do NOT Flag)
std::sync::Mutex for short critical sections — tokio docs recommend this when no .await is inside the lock
tokio::spawn without explicit join — Valid for background tasks with proper shutdown signaling
- Unbuffered channel capacity of 1 — Valid for synchronization barriers
#[tokio::main(flavor = "current_thread")] in simple binaries — Not every app needs multi-thread runtime
clone() on Arc<T> before spawn — Required for moving into tasks, not unnecessary cloning
- Large broadcast channel capacity — Valid when lagged errors are expensive (event sourcing)
Before Submitting Findings
Load and follow beagle-rust:review-verification-protocol before reporting any issue.