夜里机器替你跑全量测试,挂了还自己修:我的夜间自动巡检系统

你睡的时候,机器没睡。

我给项目搭了一套夜间全量测试 + 自动修复 的 daemon。每天凌晨 00:00,它自己拉 dev 最新代码,跑 8 步全量测试------后端单测、集成测、运营单测、运营 E2E、前端 H5 E2E、小程序编译验证。挂了,Claude Agent 自动诊断日志、切 fix 分支改代码、用完整测试套件回归一遍,过了才提 MR(不合并),飞书推个「已修复 + MR 链接」叫醒你。

第二天你打开飞书,要么是「全过」,要么是「已修复待 review」,要么是「修不动了快来」。没有「早上来发现昨晚合的代码炸了」这个选项。

这篇拆开讲这套系统怎么设计的、为什么这么设计。

整体流程:五个阶段

每次触发(定时或手动 --once)跑五个阶段,核心逻辑是:测试归测试,开发者的工作区不能动

Phase 0·预检:先把现场记下来

平台检测、Node 初始化、抢运行锁(防两个 daemon 同时跑)。关键是 save_state------把每个仓库当前的分支名记到文件里。这一步是后面无损还原的伏笔。

Phase 1·工作区准备:切到 dev,但你的改动不丢

开发者可能正卡在某个 feature 分支,有未提交的改动。脚本切 dev 之前,先把这些改动 auto-commit 一条 wip: nightly checkpoint,再 checkout dev 拉最新。你的活儿一条都不会丢。

Phase 2·全量测试:8 步,fail-fast

8 步按依赖串起来,能并行的并行(后端单测 + 前端单测一起跑)。任何一步挂,后面不跑,直接进 Phase 3。不浪费时间在已经没意义的步骤上。

Phase 3·失败处理:三种情况,三种走法

这是整套系统最有意思的地方。失败不是一刀切,分代码问题和环境问题:

  • 环境问题(后端启不来、DB 不可达):跳过修复,直接飞书告警叫人。Agent 修不了环境,硬上只会越改越乱。
  • 代码问题 (编译错、断言失败、NPE):Agent 修 → 脚本验证 → 提 MR,三步走。
  • Agent 修不动(根因定不下来):输出分析报告,不强行改,飞书通知。

代码修复这一路,有一个我特别坚持的设计:Agent 改完,不直接提 MR,先把 fix 分支拉回来跑一遍完整 8 步测试

为什么?防回归。Agent 只看了失败那一步的日志,它的修复可能把别的步骤搞挂。只重跑失败步骤会漏,必须全量回归。验证通过才提 MR;验证不过,fix 分支直接删,飞书告诉你「修复未通过验证」,宁可让人来也别合进坑。

Phase 4·恢复:always,含 trap 兜底

不管测试过没过、修没修,最后一定 restore_state ------把每个仓库切回 save_state 记录的原始分支,fix 分支也清理掉,后端停掉,锁释放。脚本被 kill(SIGTERM)时 trap 也会兜底执行。第二天你打开电脑,工作区和你昨晚离开时一模一样。

两个我觉得最值的设计

save_state / restore_state 工作区保护 。很多人搭夜间 CI,测试是跑通了,但开发者第二天发现自己分支被切走了、改动被吞了。这套用「先记后切 + auto-commit + 必然恢复」三道保险,把开发者工作区当成不可侵犯的领地。测试是测试,你的活是你的活,井水不犯河水。

修复走完整回归而非单步重试 。这是防 AI 修复的最大坑------AI 改一处容易,但它不会主动检查「这个改动会不会搞挂别人」。强制全量 8 步回归,等于把 AI 的修复也当成可疑代码审查一遍。AI 修的代码,也得过 AI 自己设的关。

自动修复的三种失败场景

落到实际,修复会撞上三种情况,脚本都做了分流:

场景 行为
Agent 改完,全量回归通过 创 MR 到 dev(不合并) + 飞书「已修复 + MR 链接」
Agent 改完,全量回归没过 删 fix 分支 + 飞书「修复未通过验证,需人工」
Agent 定不下根因 输出分析,不动代码 + 飞书通知

最后一种我特意留的------Agent 不确定就别说「已修复」 。强改只会越改越糟,不如把分析交出来让人来。这跟 PUA 那个 skill里的「穷尽方法论再说搞不定」是同一个思路:坦诚比硬撑值钱

为什么不用系统 crontab + 普通 CI

我另一套 会话级定时 review是挂在 claude 会话里的,窗口关了就停。这套不一样------它是服务器上的 daemon,独立于任何会话,7×24 跑。

跟普通 CI 的区别在「自动修复」。Jenkins/GitLab CI 跑完测试给你红灯,修不修你自己看着办。这套是红灯亮了,Agent 自动上场,修完还防回归地验一遍。CI 报问题,这套报「问题 + 已修复 + MR 待 review」。多出来的,是修复这个动作。

横向对比一下主流方案:

维度 Jenkins/GitLab CI 会话级 cron-review 这套夜间 daemon
运行位置 CI 服务器 claude 会话内 业务服务器
触发 push/PR/手动 会话内每天定时 7×24 定时
测试失败后 报红灯 报告 + 告警 自动修复 + 防回归 + MR
工作区保护 CI 隔离环境,无此问题 切分支有风险 save_state/restore_state
会话关闭 不影响 停止 不影响

这套填的空白很明确:会话级方案关了就停,普通 CI 不修。daemon 是「7×24 跑 + 失败自动修」的组合,前两个都做不到。

怎么装

bash 复制代码
# 1. 服务器上(macOS/Linux 都行,Windows 用 Git Bash)
cd /path/to/your-fullstack-repo
# 脚本已在 scripts/cron/nightly-test.sh

# 2. 配飞书通知(可选,不配也能跑)
export FEISHU_WEBHOOK_NIGHTLY_TEST="https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_TOKEN"

# 3. 服务器无桌面 Chrome,加这个
export NIGHTLY_SERVER_MODE=1

# 4. 启动 daemon(默认每天 00:00)
bash scripts/cron/nightly-test.sh start

# 自定时间 + 关闭自动修复
bash scripts/cron/nightly-test.sh start --time 02:00 --no-fix

常用命令:

命令 作用
start [--time HH:MM] [--no-fix] 启动 daemon,默认 00:00
stop 停止
status 看运行状态和上次结果
history [N] 最近 N 次历史(默认 7)
--once [--no-fix] 立即跑一次,不循环

第二天你会收到什么

飞书通知按结果分三种,一眼就知道该干啥:

全过(最常见,什么都不用做):

fallback 复制代码
[PASS] 全量测试通过
所有步骤通过。平台: macos
RUN_ID: 20260705-080000

已修复待 review(挂了但 Agent 修好了,你早上 review MR):

fallback 复制代码
[FAIL] 测试失败 --- Agent 已修复并验证通过
失败步骤: frontend-unit
修复分支: fix/nightly-20260705-080000
MR: https://codeup.aliyun.com/xxx/repo/-/merge_requests/123

修不动(Agent 也搞不定,需要人工):

fallback 复制代码
[FAIL] 测试失败 --- Agent 修复未通过验证
失败步骤: frontend-unit
修复分支: fix/nightly-20260705-080000(已清理)
需人工排查。

最关键的差别:第二种是这套系统最大的价值------你早上不用从看日志开始,直接看 MR review。第一种你忽略,第三种你才需要动手。

常见坑

部署过程中踩过几个,提前说:

claude CLI 找不到 。daemon 启动时 PATH 极简,nvm 没加载。脚本里有显式 source nvm.sh + 指定 Node 22,但你如果换机器要确认 ~/.nvm/ 路径对得上。

后端启动超时 。脚本 Step 5 拉起后端,如果 MySQL/Redis 不可达,这步会卡。确认测试库 192.168.100.67:3306:3379 网络可达------这一步环境问题,Agent 修不了,会直接飞书告警叫人。

E2E 在服务器上跑不起来 。服务器无桌面 Chrome,Playwright 找不到浏览器。必须 export NIGHTLY_SERVER_MODE=1 用 Playwright 自带的 Chromium,或者跑一次 pnpm run install:e2e

分支没切回来 。脚本被 kill -9 强杀时 trap 不执行,工作区会停在 dev 分支。用 kill(SIGTERM)别用 kill -9;真出问题了,看 .nightly-test/git-state-*.txt 手动切回去。

一个判断

测试自动化这件事,大部分人停在「自动跑测试、自动报结果」。再进一步是「测试失败自动通知」。但真正的效率瓶颈不在测试本身,在测试失败之后的修复------人早上来,看日志、定位、改、提 MR,这一套下来一上午没了。

把这一步也自动化,关键是别盲目信任 AI 的修复。AI 改的代码必须用完整套件回归一遍,过了才让它进 MR,过不了宁可退回人工。这套机制运行下来,大部分夜里挂的代码问题,第二天早上已经有 MR 等 review 了,我只需要看一眼合不合。

信任,但验证。 这是整套系统唯一的设计原则。

深度展开:夜间巡检的工程化设计

夜间巡检不是"晚上跑个 cron",是一套完整的工程化系统。核心要解决三个问题:什么时候跑、挂了怎么办、修不好怎么办

什么时候跑:凌晨 2-4 点,业务低峰期。我们用过 0 点跑,结果和数据库备份任务撞了,资源争抢导致两边都慢。后来错开到 2 点,跑完正好 4 点,运营 9 点上班时报告已经在飞书群里了。

挂了怎么办 :巡检任务自己也有可能挂(进程被 kill、OOM、机器重启)。所以巡检本身要带心跳------每 10 分钟往一个"巡检心跳文件"写时间戳,另一个监控任务扫这个文件,超过 30 分钟没更新就告警。守护进程的进程,也是工程化的一部分

修不好怎么办 :AI 自动修复只跑一次,失败就停下,把失败用例 + 错误日志 + AI 的修复尝试打包发飞书,叫人早上处理。绝不让 AI 在夜里无限重试,那是烧 token 的无底洞。

这套设计的核心判断:自动化不是为了取代人,是为了让人在早上 9 点看到一份已经梳理好的报告,而不是从零开始排查

回到本质:夜间巡检是把早晨的排查前置到凌晨用算力完成

夜间巡检的本质不是"让 AI 替我把测试跑了",而是"把人早上 9 点从零开始排查这件事,前置到凌晨用机器算力完成"。我的判断是,自动化的定位是辅助人决策,不是取代人------它产出的应该是一份已经梳理好的报告(失败用例、修复结果、剩余问题),让人在 morning 直接进入判断,而不是进入排查。

低峰跑、跑前备份、修复只跑一次、失败立刻告警、覆盖 UT/IT/E2E 三层------这些不是孤立的清单项,而是同一个判断的不同侧面:自动化必须可恢复、可收敛、可中止。无限重试是烧 token 的无底洞,连生产库跑是把测试污染成事故,任何一个失控的自治任务,都比完全不跑更糟。

工程化的标准因此不是"夜里有没有东西在跑",而是"早上你看到那份报告,能不能 5 分钟内决定下一步"。

夜间自动巡检系统的反模式

('巡检跑生产库', '直接连生产库跑测试,数据被污染。必须连独立的 test 库,或用 snapshot 还原。'), ('失败后不告警', '巡检挂了默默失败,第二天才发现。巡检挂 = 立刻告警,不能等。'), ('无限重试', '修复失败后无限重试,烧了一夜 token。修复只跑一次,失败就告警叫人。')

相关推荐
星火燎原161 小时前
Android ViewModel 接收 Intent 参数
架构
OceanBase数据库官方博客1 小时前
基于 OceanBase 湖库一体架构,构建 AI 时代的数据基础设施
人工智能·架构·oceanbase
NOVAnet20232 小时前
SaaS 化 MDR 安全运营平台技术架构解析:态势感知、关联研判与自动化响应实践
安全·架构·自动化
heimeiyingwang2 小时前
【架构实战】分布式ID生成:从自增ID到雪花算法
分布式·架构
懂AI的老郑2 小时前
面对小众场景的目标检测联合智能体零样本检测可行性分析
人工智能·yolo·架构
明哥聊AI2 小时前
AI视频生成技术全景:Sora2、Veo3、可灵3.0背后的Diffusion架构深度解析
人工智能·架构·音视频
正在走向自律5 小时前
从感知到自主决策:机器人技术的演进、核心架构与产业落地全景解析
架构·机器人·人形机器人·宇数机器人·医疗服务
木木学AI12 小时前
AI客服系统技术选型:Agentic架构与传统规则引擎的能力差异评估
人工智能·架构
满意的星月18 小时前
基于微服务和Docker容器技术的PaaS云平台架构设计(微服务架构实施原理)
docker·微服务·架构