fix(ci): 定时任务防僵尸——urlopen补超时+扫描墙钟上限+降频 [P0] #1561

Merged
xiaoxia merged 1 commits from ci/fix-scheduled-jobs-zombie-timeout into develop 2026-08-31 11:57:46 +08:00
Owner

背景

2026-08-30 CI 巡检发现 P0 级僵尸任务:pr-auto-scan 定时任务(run 42545 / task 131462)卡死 195 分钟,容器内进程阻塞在 urllib.request.urlopen()——该调用没有 timeout 参数,网络异常时永久挂起;而 Gitea 1.26.4 的 timeout-minutes: 5 对卡死 job 不生效,runner slot 被白白占用。

改动

1. scripts/ci/pr_auto_scan.py(根因修复)

  • api_request()urlopentimeout=15s,并捕获 URLError / socket.timeout / TimeoutError / OSError(返回 599,调用方按失败处理,绝不永久挂起
  • 新增 --max-wall-seconds 参数(默认 240s):整次扫描墙钟自保,到点主动退出,剩余 PR 下次调度继续处理(Gitea timeout 不可靠,脚本自己兜底)
  • merge_pr()time.sleep(30) 改为 2s 粒度可中断等待,墙钟到点立即退出

2. scripts/ci/acr_cleanup.py / scripts/ci/auto_fix_formatting.py(同款隐患一并修)

  • 全仓排查发现另外 12 处 urlopen 同样无 timeout:acr_cleanup 7 处(补 30s,生产镜像清理链路)、auto_fix_formatting 5 处(补 15s)

3. 定时工作流降频(.gitea/workflows/

  • pr-auto-scan.yml / ci-trigger-monitor.yml 的 schedule 从 */5 降到 */10
  • 两个工作流 24h 各跑 288 次 → 144 次,合计每天减少 288 次容器启动;监控告警阈值同步调整为 10 分钟(事件驱动的 pr-automation 仍实时响应,自动审批体感无影响)

影响面

  • 纯 CI 脚本/工作流改动,不碰业务代码、不碰生产部署 job
  • 已通过 black(line-length=120) / py_compile / --help 实跑校验
  • 故障佐证:8-30 当晚已手工 kill 僵尸容器并修正 DB 状态(task 131462 / job 160240 / run 42545)

后续

  • Gitea 升级(1.26.4 → 新版)后 timeout-minutes 可恢复兜底,脚本侧自保保留不冲突

🤖 Generated by [构建服务器运维] agent

## 背景 2026-08-30 CI 巡检发现 P0 级僵尸任务:`pr-auto-scan` 定时任务(run 42545 / task 131462)卡死 **195 分钟**,容器内进程阻塞在 `urllib.request.urlopen()`——**该调用没有 timeout 参数**,网络异常时永久挂起;而 Gitea 1.26.4 的 `timeout-minutes: 5` 对卡死 job 不生效,runner slot 被白白占用。 ## 改动 ### 1. `scripts/ci/pr_auto_scan.py`(根因修复) - `api_request()` 的 `urlopen` 加 **timeout=15s**,并捕获 `URLError / socket.timeout / TimeoutError / OSError`(返回 599,调用方按失败处理,**绝不永久挂起**) - 新增 `--max-wall-seconds` 参数(默认 **240s**):整次扫描墙钟自保,到点主动退出,剩余 PR 下次调度继续处理(Gitea timeout 不可靠,脚本自己兜底) - `merge_pr()` 的 `time.sleep(30)` 改为 2s 粒度可中断等待,墙钟到点立即退出 ### 2. `scripts/ci/acr_cleanup.py` / `scripts/ci/auto_fix_formatting.py`(同款隐患一并修) - 全仓排查发现另外 12 处 `urlopen` 同样无 timeout:acr_cleanup 7 处(补 30s,生产镜像清理链路)、auto_fix_formatting 5 处(补 15s) ### 3. 定时工作流降频(`.gitea/workflows/`) - `pr-auto-scan.yml` / `ci-trigger-monitor.yml` 的 schedule 从 `*/5` 降到 `*/10` - 两个工作流 24h 各跑 288 次 → **144 次**,合计每天减少 288 次容器启动;监控告警阈值同步调整为 10 分钟(事件驱动的 pr-automation 仍实时响应,自动审批体感无影响) ## 影响面 - 纯 CI 脚本/工作流改动,不碰业务代码、不碰生产部署 job - 已通过 black(line-length=120) / py_compile / --help 实跑校验 - 故障佐证:8-30 当晚已手工 kill 僵尸容器并修正 DB 状态(task 131462 / job 160240 / run 42545) ## 后续 - Gitea 升级(1.26.4 → 新版)后 `timeout-minutes` 可恢复兜底,脚本侧自保保留不冲突 🤖 Generated by [构建服务器运维] agent

🚀 预览环境已部署

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

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

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

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

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

CI全绿,自动审批通过。

CI全绿,自动审批通过。
auto-approve-bot approved these changes 2026-08-31 00:00:32 +08:00
auto-approve-bot left a comment
Collaborator

CI全绿,自动审批通过。

CI全绿,自动审批通过。
xiaoxia force-pushed ci/fix-scheduled-jobs-zombie-timeout from 20a356e7d8 to e58c45af64 2026-08-31 00:36:45 +08:00 Compare
xiaoxia force-pushed ci/fix-scheduled-jobs-zombie-timeout from e58c45af64 to 8a276dc6f9 2026-08-31 01:37:47 +08:00 Compare
xiaoxia force-pushed ci/fix-scheduled-jobs-zombie-timeout from 8a276dc6f9 to b021f56e16 2026-08-31 02:54:16 +08:00 Compare
xiaoxia added 1 commit 2026-08-31 11:28:28 +08:00
fix(ci): 定时任务防僵尸自保——urlopen补超时+扫描墙钟上限+降频
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
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 3s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) 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 / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (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 / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Validate - Type Check (mypy) (push) Has been cancelled
CI/CD Pipeline / Validate - Migration (alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (push) Has been cancelled
CI/CD Pipeline / Check push changed paths (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Build Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build API Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 3m54s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Waiting to run
3bc850dc0f
P0修复:pr_auto_scan.py 的 api_request() 中 urlopen 无 timeout,
网络异常时永久阻塞(2026-08-30 实测卡死195分钟占满runner slot),
而 Gitea 1.26.4 的 timeout-minutes 对卡死job不生效。

改动:
1. pr_auto_scan.py: urlopen 加 timeout=15s + URLError/socket.timeout
   异常捕获(返回599);新增 --max-wall-seconds(默认240s)墙钟上限,
   到点主动退出;merge_pr 的 sleep(30) 改为可中断轮询
2. acr_cleanup.py: 7处 urlopen 补 timeout=30s(生产清理链路同款隐患)
3. auto_fix_formatting.py: 5处 urlopen 补 timeout=15s
4. pr-auto-scan.yml / ci-trigger-monitor.yml: schedule 从 */5 降到 */10,
   24h运行次数各减半(288→144),监控告警阈值同步为10分钟
xiaoxia force-pushed ci/fix-scheduled-jobs-zombie-timeout from b021f56e16 to 3bc850dc0f 2026-08-31 11:28:28 +08:00 Compare
Collaborator

代码审查结果 - PR #1561

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

💡 建议(1个可选)

  1. scripts/ci/pr_auto_scan.py 第48行:异常捕获中 socket.timeoutOSError 的子类(在Python 3.3+中),因此捕获 OSError 已包含 socket.timeout。虽然显式列出两者无副作用且可读性尚可,但略显冗余,可考虑仅保留 OSError

格式检查通过 | 逻辑审查需修改 | 建议关注性能


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

## 代码审查结果 - PR #1561 ### ⚠️ 问题(0个需要修改) 无 ### 💡 建议(1个可选) 1. **scripts/ci/pr_auto_scan.py 第48行**:异常捕获中 `socket.timeout` 是 `OSError` 的子类(在Python 3.3+中),因此捕获 `OSError` 已包含 `socket.timeout`。虽然显式列出两者无副作用且可读性尚可,但略显冗余,可考虑仅保留 `OSError`。 --- ✅ 格式检查通过 | ✅ 逻辑审查需修改 | ✅ 建议关注性能 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-31 03:37:19 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit 3bc850dc0f into develop 2026-08-31 11:57:46 +08:00

🗑️ 预览环境已清理

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

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

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