ci: 瞬态故障自动重试——runner 故障时自动 re-run,无需人工干预 #1572

Merged
xiaoxia merged 1 commits from ci/transient-fault-auto-retry into develop 2026-08-31 15:23:41 +08:00
Owner

背景

run 43170 的 Frontend Lint job 在 runner-8 上 "Set up job" 阶段卡死 10m18s 超时失败(runner-8 有问题),但同一 run 其他 15 个 job 全正常。这种瞬态故障没有自动重试,白白浪费一次 CI run。

方案

ci_transient_retry.sh

独立监控脚本,每 5 分钟扫描最近 30 分钟内的 completed runs:

检测逻辑(只重试 runner 环境问题,不重试代码问题):

  • 失败 job 的第一个 step(Checkout code / Set up job)conclusion=failure → 瞬态故障特征
  • 同一 run 至少 2 个 job 成功(排除代码全挂)
  • 失败 job 占比 < 50%(多数成功 = 个别 runner 有问题)

安全措施:

  • 每个 run 最多自动重试 1 次(状态文件跟踪)
  • 状态文件 24 小时后自动清理
  • 支持 --dry-run 模式方便调试
  • 日志记录到 /var/log/ci-auto-retry.log

部署

  • systemd timer(推荐):ci_transient_retry.service + .timer
  • 或 crontab:*/5 * * * *
  • Token 通过 EnvironmentFile 注入,不硬编码

不改动的

  • 不改 ci-pipeline.yml
  • 不改 production 链路
  • 不改 auto-merge/auto-approve 逻辑

验证

dry-run 测试通过:正确识别纯代码失败(AI Code Review failure)为"非瞬态",未触发重试。

## 背景 run 43170 的 Frontend Lint job 在 runner-8 上 "Set up job" 阶段卡死 10m18s 超时失败(runner-8 有问题),但同一 run 其他 15 个 job 全正常。这种瞬态故障没有自动重试,白白浪费一次 CI run。 ## 方案 ### ci_transient_retry.sh 独立监控脚本,每 5 分钟扫描最近 30 分钟内的 completed runs: **检测逻辑(只重试 runner 环境问题,不重试代码问题):** - 失败 job 的第一个 step(Checkout code / Set up job)conclusion=failure → 瞬态故障特征 - 同一 run 至少 2 个 job 成功(排除代码全挂) - 失败 job 占比 < 50%(多数成功 = 个别 runner 有问题) **安全措施:** - 每个 run 最多自动重试 1 次(状态文件跟踪) - 状态文件 24 小时后自动清理 - 支持 `--dry-run` 模式方便调试 - 日志记录到 `/var/log/ci-auto-retry.log` ### 部署 - systemd timer(推荐):`ci_transient_retry.service` + `.timer` - 或 crontab:`*/5 * * * *` - Token 通过 EnvironmentFile 注入,不硬编码 ### 不改动的 - 不改 ci-pipeline.yml - 不改 production 链路 - 不改 auto-merge/auto-approve 逻辑 ## 验证 dry-run 测试通过:正确识别纯代码失败(AI Code Review failure)为"非瞬态",未触发重试。
xiaoxia added 1 commit 2026-08-31 14:58:53 +08:00
ci: CI 瞬态故障自动重试机制
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m28s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m19s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m22s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m26s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m20s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m21s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 5m11s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m56s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m16s
AI Code Review / AI Code Review (pull_request) Successful in 9m3s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 6m32s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 15m44s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 3m16s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 4m6s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 4m35s
115dc462d7
问题:
  当 runner 出现瞬态故障(磁盘满/docker挂/网络抖动),分配到该 runner
  的 job 会在 checkout/setup 阶段失败。这种失败与代码无关,但没有自动
  重试机制,需要人工干预。

方案:
  ci_transient_retry.sh - 每 5 分钟扫描最近 30 分钟的 runs:
  - 检测特征:失败 job 的 checkout/setup 阶段失败 + 同 run 其他 job 成功
  - 自动 re-run 整个 workflow(Gitea API /rerun)
  - 每个 run 最多重试 1 次(状态文件跟踪,24h 自动清理)
  - 支持 --dry-run 模式
  - 日志记录到 /var/log/ci-auto-retry.log

判定逻辑:
  - 失败 job 第一个 step 是 checkout/setup 且 conclusion=failure → 瞬态
  - 同一 run 至少 2 个 job 成功(排除代码全挂)
  - 纯代码失败(lint/test/compile)→ 不重试

部署:
  - systemd timer: ci_transient_retry.{service,timer}
  - 或 crontab: */5 * * * *
  - Token 通过环境变量 / EnvironmentFile 注入,不硬编码

🚀 预览环境已部署

项目 详情
PR号 #1572
预览链接 https://pr-1572.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1572 | | 预览链接 | [https://pr-1572.preview.xiaoxiajianji.com](https://pr-1572.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
Collaborator

代码审查结果 - PR #1572

⚠️ 问题(2个需要修改)

  1. scripts/ci/ci_transient_retry.sh 第113行:敏感信息泄露风险,curl 命令通过环境变量传递 Token,导致 Token 可能出现在进程列表(如 ps/proc/<pid>/cmdline)中,被同服务器其他用户窃取。
  2. scripts/ci/ci_transient_retry.sh 第274-283行(Python代码段):状态更新逻辑存在原子性问题,先调用 API 更新状态文件。如果 API 调用成功但本地状态文件写入失败(如磁盘满、权限问题),脚本会记录错误但未更新状态,导致下次执行时再次重试,引发重复执行或死循环。

💡 建议(1个可选)

  1. scripts/ci/ci_transient_retry.sh 第97行trap 命令清理临时目录时未检查变量是否存在,若 mktemp 失败导致 $TMPDIR_WORK 为空,rm -rf 可能报错或行为异常。建议改为:trap '[ -n "$TMPDIR_WORK" ] && rm -rf "$TMPDIR_WORK"' EXIT

格式检查通过 | 逻辑审查需修改 | 安全审查需修改


🤖 由 AI 代码审查机器人自动生成 | 2026-08-31 07:07:55 | 模型:

## 代码审查结果 - PR #1572 ### ⚠️ 问题(2个需要修改) 1. **scripts/ci/ci_transient_retry.sh 第113行**:敏感信息泄露风险,`curl` 命令通过环境变量传递 Token,导致 Token 可能出现在进程列表(如 `ps`、`/proc/<pid>/cmdline`)中,被同服务器其他用户窃取。 2. **scripts/ci/ci_transient_retry.sh 第274-283行(Python代码段)**:状态更新逻辑存在原子性问题,先调用 API 更新状态文件。如果 API 调用成功但本地状态文件写入失败(如磁盘满、权限问题),脚本会记录错误但未更新状态,导致下次执行时再次重试,引发重复执行或死循环。 ### 💡 建议(1个可选) 1. **scripts/ci/ci_transient_retry.sh 第97行**:`trap` 命令清理临时目录时未检查变量是否存在,若 `mktemp` 失败导致 `$TMPDIR_WORK` 为空,`rm -rf` 可能报错或行为异常。建议改为:`trap '[ -n "$TMPDIR_WORK" ] && rm -rf "$TMPDIR_WORK"' EXIT`。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ❌ 安全审查需修改 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-31 07:07:55 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit 243b0e7c78 into develop 2026-08-31 15:23:41 +08:00

🗑️ 预览环境已清理

PR #1572 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1572 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.