任务队列
English version: job-queue.md
请先阅读术语表,尤其是任务队列术语。
除单机本地基准测试外,rust-bench 可作为分布式系统运行:单个编译器/软件制品在多个 collector(机器,可能为不同架构)间并行基准测试,通过 Postgres 数据库协调。本文描述该分布式系统。按步骤的操作手册见 deploying-collector 指南。
高层概述
两个实体协作(site/src/job_queue/mod.rs、site/src/main.rs:80):
- Site 接收对某制品的基准测试请求,将每个拆分为按
(benchmark_group, collector_tag)的任务,等待所有(非可选)任务完成,然后在原始 PR/MR 上回发比较评论。 - 多个 collector 反复轮询
job_queue表寻找匹配自身名称的任务,出队一个、基准测试、将结果存入数据库。
Site 与 collector 仅通过 Postgres 数据库通信——无独立代理。Site 运行周期性 tick(默认每 30 秒,环境变量 QUEUE_UPDATE_INTERVAL_SECONDS)推进请求状态。
Site
Site 在分布式系统中的职责是创建基准测试请求、拆分为任务、标记请求完成。
创建基准测试请求
基准测试请求是 benchmark_request 中的一行(database/src/lib.rs:1227)。三种类型(BenchmarkRequestType,database/src/lib.rs:1192):
- Master——仓库
default_branch上的合并 commit。由pushwebhook(每个合并 commit 一个请求)与seed_master_commits启动流程(最近 30 天)创建。以artifacts_ready状态创建。 - Try——PR/MR 头。由
/rust-bench try [sha] [force=true]评论创建。可能以waiting_for_artifacts(尚无 SHA)或artifacts_ready(已知 SHA)起始。 - Release——已发布 tag。由
Tag Push Hook(GitCode)或 tag-refpush(GitHub),或/rust-bench tag <name>创建。以artifacts_ready创建。
每个 master/try 请求有父提交(完成后将与之比较);父提交通常应先基准测试。请求的 tag 列为制品标识(commit SHA 或发布 tag;无 SHA 的 try 请求用 try-<pr>)。
请求状态机
flowchart LR
W[waiting_for_artifacts] -->|try 构建制品出现| A
A[artifacts_ready] -->|cron 入队任务| I
I[in_progress] -->|所有非可选任务完成| C[completed]
- DB 状态字符串为下划线小写:
waiting_for_artifacts、artifacts_ready、in_progress、completed(database/src/lib.rs:1134-1147)。 waiting_for_artifacts仅用于编译器制品尚未构建的 try 请求。SHA 已知时转为artifacts_ready。- 一旦
completed,请求状态不再变化——但仍可能经回填为其生成新任务。
请求队列排序
多个请求可能同时就绪,故 Site 对其排序(job_queue/mod.rs:80-168)。优先级由高到低:
in_progress请求。artifacts_ready请求,按父完成拓扑排序——父已完成的请求优先。同一拓扑层内按 PR 号与创建时间排序。
Site 保持同时至多一个请求处于 in_progress 的不变量。即使某 collector 提前完成,也须等待 in-progress 请求的全部任务完成。这串行化运行以提高可预测性;未来可放宽。
入队任务
每次 tick,若无 in_progress 请求且至少一个 artifacts_ready,Site 将选中请求原子转为 in_progress 并向 job_queue 入队任务(mod.rs:222-362)。
对 [collectors].tags 中每个 collector tag 与请求解析的每个基准测试组(请求设了 benchmark_groups 则用之,否则用仓库配置组),各入队一个任务:
enqueue_benchmark_job(request_tag, benchmark_group, runtime_config, is_optional=false, collector_tag)——mod.rs:269-307。runtime_config为序列化的QueueRuntimeConfig(database/src/lib.rs:1627),携带仓库键、构建命令/目录、is_rust、post_build、按 collector 的覆盖项(迭代数、no_isolate、过滤器)与extra_args。
任务以 (request_tag, benchmark_group, tag) 唯一——此处 tag 为存储结果时使用的 collector tag。重复入队为 no-op(JobExistedOrParentNotFound)。
任务状态机(database/src/lib.rs:1462):
flowchart LR
Q[queued] -->|首次出队| I
I[in_progress] -->|成功| S[success]
I -->|失败 重试<MAX| I
I -->|失败 重试=MAX| F[failure]
入队后,tick 反复检查 in-progress 请求的全部(非可选)任务(及其父任务——见回填)是否完成。完成时请求转为 completed 并回发比较评论(mod.rs:538-639)。Release 请求不发评论。
回填
入队请求任务时,Site 也为其父请求入队相同任务(mod.rs:337-349)。父通常已有结果,故常见情况下父任务已存在,插入为 no-op。
当请求使用父从未基准测试过的非默认参数时回填才有意义——如 try 请求基准测试了父 master 运行未包含的基准测试组。会为父以这些参数创建新任务;collector 运行并将结果"回填"进已完成的父请求。父状态保持 completed。
Collector
每个 collector 的职责是出队任务、运行、存储结果。操作手册见 deploying-collector 指南。
注册
collector 注册于 collector_config 表(name 唯一)。注册:
cargo run --bin collector add_collector \
--db "postgres://user:pass@host/db" \
--collector_name "Kunpeng 920B" \
--is_active
add_collector 插入 name、date_added、last_heartbeat_at、is_active(collector/src/bin/collector.rs:689)。commit_sha 运行时更新。仅 is_active = true 的 collector 接收任务。collector_name 必须匹配 [collectors].tags 中某项,Site 才会为其入队任务。
必须 Postgres。
benchmark_job_queue不支持 SQLite。
出队任务
cargo run --bin collector benchmark_job_queue \
--db "postgres://..." --collector_name "Kunpeng 920B" \
--check_git_sha --git_sha <sha>
启动后,collector 轮询 job_queue(每 30 秒)寻找 collector_name 匹配且 status 为 queued 或自身已 in_progress 的任务。出队时标记 in_progress、递增 retry(出队计数),然后按 runtime_config 构建/拉取制品并运行全部测试用例。
失败处理与重试
三种失败(collector/src/bin/collector.rs 的 benchmark_job_queue 处理器):
- 已处理瞬态(网络/DB 错误):错误记入
errors表;任务保持in_progress,稍后再次出队。 - 已处理永久(如该 SHA 制品不可用):记录错误;任务标记
failure;collector 继续。 - 未处理(panic):
collectorsystemd/脚本重启进程;in-progress 任务下次循环再次出队(其retry计数已递增)。
若 collector 出队的任务 retry 已达 MAX_RETRIES,则标记为 failure。自身 in-progress 任务优先于新 queued 任务。
自动 git 更新
collector/collect-job-queue.sh 循环运行 collector。每次迭代前执行 git pull && git reset --hard @{upstream}、rustup update stable、cargo build --release -p collector --features s3-sdk。配合 --check_git_sha,运行中的 collector 将自身 SHA 与仓库 HEAD 比较;若有更新则关闭(延迟至 in-progress 请求完成),以便脚本重建。
心跳
collector 周期性更新 collector_config.last_heartbeat_at。状态页显示心跳;心跳过旧则标记 collector 为 Offline。持有 in-progress 任务的已停 collector 将使整个系统停滞,直到人工干预,因为 collector tag 间无工作窃取。