跳至内容

队列与重试

queue 命名空间决定评审任务在哪里排队、同时跑多少个、对每个 provider 的调用多快、 以及任务失败时怎么重试。默认是内存队列;生产环境建议切换到持久化 SQLite 队列, 让任务在重启后仍然存在。

queue:
kind: sqlite # memory(默认)| sqlite | redis
workers:
concurrency: 4
per_workspace_concurrency: 1
lock_ttl_seconds: 1800
rate_limit:
per_provider_rps:
gitea-internal: 5
retry:
attempts: 3
backoff:
kind: exponential
base_ms: 2000
max_ms: 60000
jitter: true
取值 说明
memory(默认) 进程内队列,重启即丢失。适合单实例开发。
sqlite 持久化队列,重启后仍在(单进程或多进程共享同一文件)。生产推荐。
redis 持久化到 Redis,适合多实例部署。配置见下。
rabbitmq 预留——尚未实现,配置了会告警并回退到 memory

Redis 队列的连接字段以透传方式接受:

字段 类型 默认 说明
url_env string 存放 Redis URL 的环境变量名。
url string 直接写 Redis URL(也可拆成 host / port / password / db)。
tls bool false 使用 TLS 连接。
key_prefix string "aicr:" 队列键前缀。共享 Redis 时请按环境取唯一值。
字段 类型 默认 说明
concurrency int > 0 4 全局 worker 并发(进程内同时运行的任务数)。
per_workspace_concurrency int > 0 1 每个 workspace 同时运行的任务上限。设为 1 可按仓库串行。
lock_ttl_seconds int > 0 1800 worker 任务锁 TTL。
字段 类型 默认 说明
path string data/queue.sqlite 队列使用的 SQLite 数据库文件。
lock_ttl_seconds int > 0 300 陈旧运行回收 TTL。运行锁早于该时长的任务视为崩溃并被回收。

SQLite 队列基于 better-sqlite3, 单进程或多个进程共享同一文件都安全。关键特性:

  • UPDATE ... RETURNING 原子领取。 worker 用单条语句领取下一个 queued 任务并标记为 running,因此两个 worker 永远不会抢到同一个任务。
  • 锁 TTL 后回收陈旧任务。 后台扫描会把运行锁早于 lock_ttl_secondsrunning 任务重新入队,因此崩溃 worker 的任务最终会被其他 worker 重试。
  • WAL + busy_timeout 保证跨进程安全。 队列以 PRAGMA journal_mode = WALPRAGMA busy_timeout = 5000 打开,来自不同进程的并发写入会协作而非报错。
字段 类型 说明
per_provider_rps map<string, number> 按 provider id 设置的每秒请求数上限。
queue:
rate_limit:
per_provider_rps:
gitea-internal: 5 # 对 gitea-internal provider 最多 5 rps

queue.retry —— 请用 attempts + backoff

Section titled “queue.retry —— 请用 attempts + backoff”

规范字段

规范的重试字段是 attemptsbackoff。旧字段 max_attempts / backoff_seconds 仍然会被接受并归一化,但已弃用—— 请迁移到 attempts + backoff

字段 类型 默认 说明
attempts int > 0 3 总尝试次数(含首次)。1 = 不重试。
backoff.kind enum exponential exponentiallinearconstant
backoff.base_ms number > 0 5000 首次/基础退避延迟(毫秒)。
backoff.max_ms number > 0 60000 单次退避延迟上限。
backoff.jitter bool true 是否加入随机抖动。

trigger 级重试用于吸收瞬时 IO 失败(超时、连接重置、DNS 抖动、HTTP 408/5xx)。 只有被分类为瞬时的错误才会重试;确定性失败——尤其是 context_overflow—— 无论 attempts 是多少都不会重试。更细粒度的重试发生在下一层:LLM provider 调用、输出渠道 fetch、VCS CLI 网络操作、GitHub App token 交换与 issue triage API 客户端,各自对瞬时 IO 错误按短指数退避最多重试 3 次,之后才把整个 trigger run 判为失败。输出与 triage 层只对幂等方法重试;非幂等 POST 永不重试, 响应丢失不会导致 issue 或评论重复。HTTP 429 交由 LLM gateway 按 Retry-After 处理。

queue:
retry:
attempts: 3 # 瞬时失败重试(1 = 不重试)
backoff:
kind: exponential
base_ms: 5000
max_ms: 60000
jitter: true

旧字段(已弃用,会被归一化)

Section titled “旧字段(已弃用,会被归一化)”

为向后兼容,加载器仍会读取并归一化这些字段,但新配置不应再使用:

旧字段 归一化为
max_attempts attempts(向下取整)。
backoff_seconds 一个 constant 退避,base_ms = max_ms = backoff_seconds * 1000jitter: false

两者同时存在时,attempts / backoff 始终优先。

queue.dead_letter —— 预留,尚未生效

Section titled “queue.dead_letter —— 预留,尚未生效”

schema 接受 dead_letter.enableddead_letter.max_age_hours 两个字段,但当前 运行时没有消费它们:重试耗尽的任务按失败处理并写入运行历史,没有独立的停放区。 这两个字段保留给后续版本,现在配置不会产生任何行为。