任务队列

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。由 push webhook(每个合并 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-ref push(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)。优先级由高到低:

  1. in_progress 请求。
  2. 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):collector systemd/脚本重启进程;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 间无工作窃取。