mcpField
T
tokio-async-code-review

tokio-async-code-review

github.com/existential-birds测试与质量8590 次安装11 周前更新
代码仓库

关于 tokio-async-code-review

tokio-async-code-review 是面向 Rust 代码审查者的 Tokio 异步代码检查技能。它覆盖运行时、阻塞操作、任务、同步原语和通道,并要求依据依赖与代码位置验证问题。

主要功能

  1. 01检查 Tokio 依赖与功能标志
  2. 02确认运行时模型
  3. 03扫描异步代码中的阻塞操作
  4. 04审查任务与同步原语
  5. 05核对通道模式和取消安全

适用场景

  1. 01审查 Tokio 功能标志与运行时配置
  2. 02查找异步函数中的阻塞调用
  3. 03检查任务句柄与错误处理
  4. 04评估锁、通道和取消行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/existential-birds/beagle --skill tokio-async-code-review

安装后在 Claude Code 中输入/tokio-async-code-review确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
channels.md
pinning-cancellation.md
sync-primitives.md
task-management.md

详细介绍

Tokio 异步代码审查

审查工作流

  1. 检查 Cargo.toml — 记录 tokio 功能标志(full、rt-multi-thread、macros、sync 等)。缺少功能会导致令人困惑的编译错误。
  2. 检查运行时设置 — 使用了 #[tokio::main] 还是手动构建运行时?采用多线程还是当前线程?
  3. 扫描阻塞操作 — 在异步函数中搜索 std::fs、std::net、std::thread::sleep 和 CPU 密集型循环。
  4. 检查通道用法 — 根据通信模式匹配通道类型(mpsc、broadcast、oneshot、watch)。
  5. 检查同步原语 — 确认互斥锁类型正确、守卫的生命周期恰当,且不存在潜在死锁。

关卡(得出结论前的客观检查项)

按照顺序完成与审查范围相关的检查。在相关关卡通过之前,不要断言存在 Critical 或 Major 问题。

  1. 依赖范围 — 阅读提供 tokio 的 crate 的 Cargo.toml(如果继承自 workspace,也要阅读 workspace 的 Cargo.toml)。通过条件: 写明 tokio 版本和启用的功能,或明确说明没有直接的 tokio 依赖,并注明其来源(workspace/path)。
  2. 运行时模型 — 找出运行时的构建位置(#[tokio::main]、Runtime::builder、测试,或不拥有运行时的库)。通过条件: 用一行说明运行时类型(multi_thread / current_thread / 仅测试 / 无),并注明定义位置。
  3. 阻塞操作清单 — 搜索已审查路径中的阻塞 API(std::fs::、没有异步封装的 std::net::、std::thread::sleep、async fn 中的高开销 CPU 循环)。通过条件: 将每个命中项列为 path:line(或工具输出摘录),或在搜索后明确写明“已审查的异步代码中未发现阻塞模式”。
  4. 协议 — 加载 review-verification-protocol 技能。通过条件: 在报告任何发现之前满足其通过条件(断言问题时提供文件:行号证据)。

输出格式

按以下格式报告发现:

[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.

快速参考

问题类型参考资料
任务生成、JoinHandle、结构化并发references/task-management.md
Mutex、RwLock、Semaphore、Notify、Barrierreferences/sync-primitives.md
mpsc、broadcast、oneshot、watch 通道模式references/channels.md
Pin、取消、Future 内部机制、select!、阻塞桥接references/pinning-cancellation.md

审查清单

运行时配置
  • Cargo.toml 中的 Tokio 功能与实际用法一致
  • 运行时类型与工作负载匹配(I/O 密集型使用 multi_thread,简单场景使用 current_thread)
  • 异步测试使用 #[tokio::test](而非手动构建运行时)
  • 为生产环境适当配置工作线程数量
任务管理
  • 跟踪 spawn 的返回值(JoinHandle),而不是静默丢弃
  • 对 CPU 密集型或同步 I/O 操作使用 spawn_blocking
  • 任务能够响应取消(通过 CancellationToken、select! 或关闭通道)
  • 处理 JoinError(任务 panic 或取消),而不是只使用 unwrap
  • tokio::select! 分支可安全取消
  • 尽可能使用 trait 中原生的 async fn,而非 async-trait crate(自 Rust 1.75 起已稳定)
  • 检查异步上下文中的 RPIT 生命周期捕获——在 edition 2024 中,-> impl Future 现在会捕获作用域内的所有生命周期
同步原语
  • 跨 .await 持有锁时使用 tokio::sync::Mutex;短暂的非异步代码段使用 std::sync::Mutex
  • 不要跨越 await 点持有互斥锁守卫(有死锁风险)
  • 使用 Semaphore 限制并发操作(而非临时计数器)
  • 读操作较多时使用 RwLock(读者众多、写入较少)
  • 使用 Notify 进行简单通知(避免通道开销)
  • 对运行时初始化的单例使用 std::sync::LazyLock,而非 once_cell::sync::Lazy 或 lazy_static!(自 Rust 1.80 起稳定)
  • 检查 if let 锁守卫模式是否受 edition 2024 临时值作用域影响——临时值会更早释放,可能改变借用的有效性
通道
  • 通道类型与模式相匹配:mpsc 用于背压,broadcast 用于扇出,oneshot 用于请求-响应,watch 用于最新值
  • 有界通道的容量设置恰当(太小会导致死锁,太大会占用内存)
  • 处理 SendError / RecvError(表示另一端已被丢弃)
  • 处理 broadcast 的 Lagged 错误(接收方未能跟上)
  • 完成后丢弃通道发送方,以向接收方发出完成信号
定时器与休眠
  • 使用 tokio::time::sleep,而非 std::thread::sleep
  • 对可能挂起的操作使用 tokio::time::timeout 包装
  • 正确使用 tokio::time::interval(周期性工作使用 .tick().await)

严重性分级

严重
  • 在异步上下文中使用阻塞式 I/O(std::fs::read、std::net::TcpStream),且未使用 spawn_blocking
  • 跨 .await 点持有互斥锁守卫(有潜在死锁风险)
  • 在异步函数中使用 std::thread::sleep(阻塞运行时线程)
  • 需要背压的场景使用无界通道(有 OOM 风险)
主要
  • 静默丢弃 JoinHandle(错误丢失、任务变成僵尸)
  • 未考虑 select! 的取消安全性
  • 根据使用场景选择了错误的互斥锁类型(std 或 tokio)
  • 网络/外部操作缺少超时设置
次要
  • 对极小的异步代码块使用 tokio::spawn(开销大于收益)
  • 通道缓冲区过大且没有合理依据
  • #[tokio::main] 已足够时仍手动构建运行时
  • 争用程度高到适合使用 tokio 异步互斥锁时,仍使用 std::sync::Mutex
提示信息
  • 建议使用 tokio-util 工具(例如 CancellationToken)
  • 用于服务组合的 Tower 中间件模式
  • 使用 JoinSet 实现结构化并发
  • 从 async-trait crate 迁移到 trait 中的原生 async fn
  • 从 once_cell / lazy_static 迁移到 std::sync::LazyLock
  • 使用 #[expect(lint)] 代替 #[allow(lint)],以便在不再需要抑制时自动清理

有效模式(不要标记)

  • 短临界区使用 std::sync::Mutex — tokio 文档建议在锁内没有 .await 时使用此方式
  • 使用 tokio::spawn,但不显式等待其完成 — 对于具有适当关闭信号的后台任务,这是有效的
  • 容量为 1 的无缓冲通道 — 可用于同步屏障
  • 简单二进制程序中使用 #[tokio::main(flavor = "current_thread")] — 并非所有应用都需要多线程运行时
  • 在 spawn 前对 Arc<T> 调用 clone() — 将其移入任务所必需,并非不必要的克隆
  • 容量较大的 broadcast 通道 — 当 Lagged 错误代价较高时(事件溯源),这是有效的
  • trait 中不使用 async-trait 的原生 async fn — 自 1.75 起稳定;在 dyn 分发场景中,该 crate 仍然有效
  • -> impl Future 返回类型中的 + use<'a> — 这是正确的 edition 2024 精确捕获语法,可限制生命周期捕获
  • 复杂异步类型上使用 #[expect(clippy::type_complexity)] — 这是 #[allow] 的自动清理替代方案,当不再需要抑制时会发出警告

提交发现前

完成 Gates 后,对每个报告的问题应用 review-verification-protocol 技能(证据和处理方式遵循该技能的要求)。

评论

支持 Markdown