Compare commits

..

36 Commits

Author SHA1 Message Date
root
215a364891 feat: stabilize multi-region runtime sync and worker orchestration 2026-04-27 15:48:12 +08:00
Your Name
7cbde2aa78 d 2026-04-22 14:13:21 +08:00
Your Name
e0406b5d0e Update runtime handoff after mainland deploy validation 2026-04-19 03:43:19 +08:00
Your Name
c33f4f194b Fix worker control fallback for running detect workers 2026-04-19 03:32:56 +08:00
Your Name
451d0f75f0 docs: capture mainland sync-agent blocker 2026-04-19 03:00:53 +08:00
Your Name
66f55d880a fix: auto-project mainland detect sync 2026-04-19 02:59:10 +08:00
Your Name
4dcbf8ecb3 feat: ingest mainland detect result events 2026-04-19 02:53:43 +08:00
Your Name
3a55db94f8 docs: capture mainland result sync prerequisite 2026-04-19 02:44:30 +08:00
Your Name
6c4e995f84 fix: unify detect effective job metrics 2026-04-19 02:41:45 +08:00
Your Name
cfff515c03 fix: surface distributed detect participation 2026-04-19 02:35:43 +08:00
Your Name
ad513211e6 docs: move ops runtime tracking under docs 2026-04-19 02:27:06 +08:00
Your Name
74dc009c3d fix: inherit sync env in node agent 2026-04-19 02:22:56 +08:00
Your Name
1adfeed1ab fix: dispatch detect start to mainland nodes 2026-04-19 02:18:42 +08:00
Your Name
b9c29481b5 feat: add ops center and node onboarding flow 2026-04-18 23:52:51 +08:00
root
246838ae4c fix runtime ingest effective worker projection 2026-04-17 16:50:55 +08:00
Your Name
bd6bcb240f debug 2026-04-17 16:17:19 +08:00
Your Name
0e096947fc debug 2026-04-17 15:13:46 +08:00
Your Name
fe87c7b343 debug 2026-04-17 14:19:26 +08:00
Your Name
1921318c25 debug 2026-04-17 14:07:50 +08:00
Your Name
dc34a4e294 debug 2026-04-17 12:30:31 +08:00
Your Name
954a6a2c65 debug 2026-04-17 03:45:36 +08:00
Your Name
d3223a75a4 debug 2026-04-17 03:36:03 +08:00
Your Name
3cc36a054c debug 2026-04-17 03:13:54 +08:00
Your Name
f4b4ed0afe debug 2026-04-17 02:35:37 +08:00
Your Name
602ab10590 dd 2026-04-17 02:11:01 +08:00
Your Name
e9c0a75b8f debug 2026-04-17 01:04:11 +08:00
Your Name
25d36c9d4b debug 2026-04-16 23:00:25 +08:00
Your Name
0d8c0b4aed debug 2026-04-16 22:41:13 +08:00
Your Name
ff79f5c13d dd 2026-04-16 22:38:18 +08:00
Your Name
6ed4a99143 debug 2026-04-16 22:35:08 +08:00
Your Name
9aa0d87c4a debug 2026-04-16 22:29:58 +08:00
Your Name
a48a4131c9 debug 2026-04-16 22:23:52 +08:00
Your Name
0295f7d06d d 2026-04-16 22:14:45 +08:00
Your Name
e64c23a021 debug 2026-04-16 22:07:45 +08:00
Your Name
ebf632e651 first 2026-04-16 21:35:47 +08:00
Your Name
ff32aa50bf docs: add linux handoff and wayback env example 2026-04-16 13:43:50 +08:00
388 changed files with 166875 additions and 1886 deletions

35
.gitignore vendored
View File

@@ -21,8 +21,11 @@ dist/
# Logs and runtime data # Logs and runtime data
*.log *.log
logs/ *.pid
runtime/ /runtime/
/diagnostics/
/domain-api/runtime/
!/domain-web/src/views/runtime/
# Build and release artifacts # Build and release artifacts
release/ release/
@@ -31,19 +34,45 @@ release/
# Local data and generated files # Local data and generated files
uploads/ uploads/
exports/ /logs/
/exports/
tmp/ tmp/
*.sqlite3 *.sqlite3
*.pkl *.pkl
domains.txt domains.txt
credentials.json credentials.json
!/domain-web/src/views/logs/
!/domain-web/src/views/exports/
# Local deploy config copies
domain-api/deploy/multi-region/*.conf
!domain-api/deploy/multi-region/*.conf.example
# domainCheck local runtime / bundled tools # domainCheck local runtime / bundled tools
domainCheck/tools/node-v20.19.4-win-x64/ domainCheck/tools/node-v20.19.4-win-x64/
domainCheck/app/credentials.json domainCheck/app/credentials.json
domainCheck/credentials.json domainCheck/credentials.json
domainCheck/runtime/
domainCheck/**/*.pkl domainCheck/**/*.pkl
domainCheck/domains.txt domainCheck/domains.txt
thread_count.json
node_thread_counts.json
runtime_settings.json
runtime/runtime_settings.json
runtime/sensitive_words.json
# Ops center generated night-run artifacts
docs/ops_center_runtime/night_runs/night_run_*/
docs/ops_center_runtime/night_runs/night_run_*_summary.json
docs/ops_center_runtime/night_runs/*.log
docs/ops_center_runtime/night_runs/*.pid
docs/ops_center_runtime/night_runs/step_mix_*/
docs/ops_center_runtime/chinaz_gray_runs/
docs/_tmp_regression/
# Local probe / backup artifacts
.codex-release-probe.txt
*.bak_*
# OS / editor # OS / editor
.DS_Store .DS_Store

View File

@@ -6,13 +6,24 @@
- 新版后端服务 `domain-api/` - 新版后端服务 `domain-api/`
- 新版 Web 管理后台 `domain-web/` - 新版 Web 管理后台 `domain-web/`
- 全套交付与部署文档 `docs/` - 全套交付与部署文档 `docs/`
- Windows 本地启动、打包、验包脚本 - Windows / Linux 启动、打包、验包脚本
如果你是第一次打开这个仓库,建议先看: 如果你是第一次打开这个仓库,建议先看:
- [docs/12_domainCheck_导航索引.md](./docs/12_domainCheck_导航索引.md) - [docs/12_domainCheck_导航索引.md](./docs/12_domainCheck_导航索引.md)
- [docs/04_domainCheck_WebLinux改造总体方案.md](./docs/04_domainCheck_WebLinux改造总体方案.md) - [docs/04_domainCheck_WebLinux改造总体方案.md](./docs/04_domainCheck_WebLinux改造总体方案.md)
如果你当前已经进入“海外单脑控制面 / 多机联调 / 准备上线”阶段,建议直接从下面 4 份开始:
1. [docs/25_domainCheck_海外单脑控制面上线收口总表.md](./docs/25_domainCheck_海外单脑控制面上线收口总表.md)
2. [docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md](./docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md)
3. [docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md](./docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md)
4. [docs/schemas/ops_driver_contract.md](./docs/schemas/ops_driver_contract.md)
如果已经接近正式发布,建议再补一份:
- [docs/26_domainCheck_发布前运行验证与交付模板.md](./docs/26_domainCheck_发布前运行验证与交付模板.md)
## 目录结构 ## 目录结构
```text ```text
@@ -25,10 +36,14 @@
├─ start_*.ps1 Windows 启动脚本 ├─ start_*.ps1 Windows 启动脚本
├─ stop_*.ps1 Windows 停止脚本 ├─ stop_*.ps1 Windows 停止脚本
├─ smoke_test_stack.ps1 本地整栈自测 ├─ smoke_test_stack.ps1 本地整栈自测
├─ package_domain_release.ps1 交付打包 ├─ package_domain_release.ps1 Windows 交付打包
├─ verify_domain_release.ps1 交付包校验 ├─ verify_domain_release.ps1 Windows 交付包校验
├─ prepare_final_release.ps1 最终发布准备 ├─ prepare_final_release.ps1 Windows 最终发布准备
─ show_latest_release.ps1 查看最新交付包 ─ show_latest_release.ps1 Windows 查看最新交付包
├─ package_domain_release.sh Linux / 海外主机交付打包
├─ verify_domain_release.sh Linux / 海外主机交付包校验
├─ prepare_final_release.sh Linux / 海外主机最终发布准备
└─ show_latest_release.sh Linux / 海外主机查看最新交付包
``` ```
## 各目录用途 ## 各目录用途
@@ -118,6 +133,15 @@
- [verify_domain_release.ps1](./verify_domain_release.ps1) - [verify_domain_release.ps1](./verify_domain_release.ps1)
- [prepare_final_release.ps1](./prepare_final_release.ps1) - [prepare_final_release.ps1](./prepare_final_release.ps1)
- [show_latest_release.ps1](./show_latest_release.ps1) - [show_latest_release.ps1](./show_latest_release.ps1)
- [package_domain_release.sh](./package_domain_release.sh)
- [verify_domain_release.sh](./verify_domain_release.sh)
- [prepare_final_release.sh](./prepare_final_release.sh)
- [show_latest_release.sh](./show_latest_release.sh)
补充说明:
- `show_latest_release.ps1 / .sh` 现在会校验 `final_release_report.json` 是否真的对应当前 `latest_release.*`
- 不是“目录里有 final report 就算已经完成最终签收”
## 当前状态 ## 当前状态
@@ -142,6 +166,69 @@ Linux 阶段建议先看:
- [docs/11_domainCheck_Linux联调输入清单.md](./docs/11_domainCheck_Linux联调输入清单.md) - [docs/11_domainCheck_Linux联调输入清单.md](./docs/11_domainCheck_Linux联调输入清单.md)
- [docs/12_domainCheck_导航索引.md](./docs/12_domainCheck_导航索引.md) - [docs/12_domainCheck_导航索引.md](./docs/12_domainCheck_导航索引.md)
如果当前已经切到“海外单脑控制面 + 大陆托管节点 + 发布 / Rollout / 驾驶舱首屏”阶段,建议改为:
1. [docs/25_domainCheck_海外单脑控制面上线收口总表.md](./docs/25_domainCheck_海外单脑控制面上线收口总表.md)
2. [docs/22_domainCheck_海外Codex驾驶员与OpsCenter落地路线.md](./docs/22_domainCheck_海外Codex驾驶员与OpsCenter落地路线.md)
3. [docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md](./docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md)
4. [docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md](./docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md)
5. [docs/schemas/ops_stack_diagnosis_contract.md](./docs/schemas/ops_stack_diagnosis_contract.md)
6. [docs/schemas/ops_driver_contract.md](./docs/schemas/ops_driver_contract.md)
如果当前已经进入“海外主机集中运维 / 多机联调 / Release Hub”阶段最直接的统一入口是
- [domain-api/deploy/multi-region/drive_ops_center.sh](./domain-api/deploy/multi-region/drive_ops_center.sh)
- [domain-api/deploy/multi-region/drive_release_hub.sh](./domain-api/deploy/multi-region/drive_release_hub.sh)
- [domain-api/deploy/multi-region/drive_ops_action.sh](./domain-api/deploy/multi-region/drive_ops_action.sh)
- [domain-api/deploy/multi-region/init_ops_center_config.sh](./domain-api/deploy/multi-region/init_ops_center_config.sh)
其中:
- `drive_ops_center.sh`
用于海外控制面统一调度检查、Release Hub 和 Driver 动作
- `drive_release_hub.sh`
用于直接从命令行走 Release / Rollout 标准接口
- `drive_ops_action.sh`
用于直接从命令行走 `ops/driver-actions/execute`
- `init_ops_center_config.sh`
用于初始化 `/etc/default/domaincheck-ops-center`
现在 `drive_ops_center.sh` 还额外收进了本机发布链:
- `release-package`
- `release-verify`
- `release-show`
- `release-launchpad`
- `release-prepare`
- `release-preview`
- `release-preview-smart`
当前如果要用一条最短路径判断“现在能不能继续收口、能不能继续发布”,推荐先跑:
```bash
cd /www/wwwroot/getDomain
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-check http://127.0.0.1:8100 http://127.0.0.1:8100 summary
```
然后再按:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh stack-diagnosis
bash domain-api/deploy/multi-region/drive_ops_center.sh driver-feed
bash domain-api/deploy/multi-region/drive_ops_center.sh codex-brief
```
继续下钻。
如果要把这轮检查直接导出成一整包上线证据,也可以直接执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-export
```
它会把 `go-live / stack-diagnosis / driver-feed / codex-brief / release-launchpad / doctor-*`
统一导出到 `domain-api/runtime/ops-center-reports/go-live-bundles/` 下,并生成一份 `manifest.json`
## Git 提交建议 ## Git 提交建议
建议提交: 建议提交:

View File

@@ -1,90 +1,231 @@
# 07 domainCheck Web/Linux 发布验收清单 # 07 domainCheck Web/Linux 发布验收清单
## 一、基础连通 ## 一、文档定位
- `domain-api` 已启动 本文档用于回答两个问题:
- `domainCheck Worker` 已启动
- `http://服务器IP:8100/health` 返回 `status=ok`
- `runtime/preflight` 返回 `ok=true`
## 二、Web 后台 1. 当前这套 Web/Linux 方案,到底哪些项已经验过
2. 发布前还需要按什么维度再核一遍
阅读建议:
- 想看测试服真实联调结果,优先看 `docs/13_domainCheck_Linux测试服交接文档.md`
- 想看正式上线前最后一次操作顺序,优先看 `docs/14_domainCheck_正式上线前最终检查单.md`
本文档更适合作为“发布验收维度总表”。
## 二、基础连通验收
以下项目应视为发布验收的第一层:
- `domaincheck-api` 已启动
- `domaincheck-worker` 已启动
- `http://127.0.0.1:8100/health` 返回 `status=ok`
- `/health` 返回 `worker_mode=linux-systemd`
- `/api/v1/runtime/preflight` 返回 `ok=true`
- `/api/v1/runtime/status` 返回 `worker.running=true`
当前测试服状态:
- 已验证通过
## 三、Web 后台验收
### 1. 运行与展示
- 登录正常 - 登录正常
- 顶部可看到 `API / Worker / 运行模式` - 顶部状态可展示 `API / Worker / 运行模式`
- 概览页正常读取统计 - 概览页正常读取统计
- 运行中心正常读取: - 运行中心正常读取:
- API 版本 - API 版本
- API 前缀 - API 前缀
- PID - PID
- Worker 进程数 - Worker 进程数
- 自检结果 - 自检结果
## 三、配置能力 ### 2. 配置能力
- 系统设置正常读取 - 系统设置正常读取
- 线程数修改后可保存 - 线程数修改保存
- 检测顺序可调整并保存 - 检测顺序可调整并保存
- 代理池列表可编辑并保存 - 代理池列表可编辑并保存
- `worker_mode / service_name` 可保存 - `worker_mode / worker_service_name / api_service_name` 可保存
- 可手动创建配置备份 - 可手动创建配置备份
- 可下载配置备份 - 可下载配置备份
- 可导出配置快照 - 可导出配置快照
- 可导入配置快照 - 可导入配置快照
- 导入配置时会自动生成导入前备份 - 导入配置时会自动生成导入前备份
## 四、业务能力 当前测试服状态:
- 核心接口与配置链路已验证通过
## 四、业务能力验收
发布前建议至少覆盖下面 5 类能力:
- 导入
- 列表筛选
- 批量更新
- 导出
- 日志与诊断
### 1. 导入链路
- 导入任务可创建 - 导入任务可创建
- 导入任务列表可刷新 - 导入任务列表可刷新
- 导入任务失败时可重试 - 导入结果统计正确
- 域名筛选可查询 - 导入成功后会写入 `domains`
- 批量更新可执行 - 导入成功后会自动创建 `detect_tasks`
- 导出记录可生成
- 导出文件可下载
- 日志诊断页可查看日志
- 诊断包可下载
## 五、Linux 特有项 当前测试服状态:
- 已使用样本 TXT 实际验证通过
- 当前已确认:
- 总数 `5`
- 有效 `3`
- 新增 `3`
- 无效 `2`
### 2. 列表与筛选
- 域名列表可查询
- 筛选项接口正常返回
- 页面结果与数据库记录一致
当前测试服状态:
- 已验证通过
### 3. 批量更新
- 批量更新接口可执行
- 页面展示与数据库字段一致
- 关联检测字段会同步更新
当前测试服状态:
- 已验证通过
- 已确认 `backlink_count_gt_10` 可随批量更新同步生效
### 4. 导出链路
- 导出任务可创建
- 导出记录可查看
- 导出文件可下载
- TXT / CSV 至少一种格式已回归
当前测试服状态:
- TXT、CSV 均已验证通过
### 5. 日志与诊断
- 日志接口可正常读取
- 诊断包可正常导出
当前测试服状态:
- 已验证通过
- 当前已生成正式服务态诊断包:
- `/opt/domaincheck/diagnostics/diag_20260416_134923.tar.gz`
## 五、Linux 特有项验收
以下项目是 Web/Linux 交付里最容易在正式环境出问题的部分:
- `domaincheck-api.service` 可正常启动/停止 - `domaincheck-api.service` 可正常启动/停止
- `domaincheck-worker.service` 可正常启动/停止 - `domaincheck-worker.service` 可正常启动/停止
- `journalctl` 可查看两边日志 - `journalctl` 可查看两边日志
- Nginx 反代正常 - 运行中心可调用 `start_worker / stop_worker / restart_api`
- Web 静态文件 `dist` 已正确发布 - Worker 以 `QT_QPA_PLATFORM=offscreen` 正常运行
- API 自重启不会再因为同步等待自身停机而误报 `500`
## 六、建议发布前命令 当前测试服状态:
### 1. 运行 API 自测 - 已验证通过
## 六、数据库与权限验收
Linux 新环境发布前,下面两项必须显式确认:
### 1. 数据库初始化
如果 PostgreSQL 使用的是新库,必须先执行:
```bash ```bash
cd /opt/domaincheck/domain-api cd /opt/domaincheck/domainCheck
python deploy/linux/smoke_test.py --base-url http://127.0.0.1:8100 python3 init_database.py
```
否则至少这些接口会直接失败:
- `/api/v1/dashboard/overview`
- `/api/v1/detect/status`
- `/api/v1/imports/summary`
### 2. 服务用户写权限
正式 `systemd` 服务用户必须可写:
- `domain-api/runtime/`
- `domainCheck/detect_worker.log`
否则可能出现:
- `/api/v1/imports/upload` 返回 `500`
- Worker 循环重启
当前测试服状态:
- 两项都已实际踩坑并修复
## 七、发布前建议命令
### 1. 健康检查
```bash
curl http://127.0.0.1:8100/health
curl http://127.0.0.1:8100/api/v1/runtime/preflight
curl http://127.0.0.1:8100/api/v1/runtime/status
```
### 2. systemd 状态
```bash
systemctl status domaincheck-api --no-pager -l
systemctl status domaincheck-worker --no-pager -l
```
### 3. smoke test
```bash
cd /opt/domaincheck/domain-api/deploy/linux
python3 smoke_test.py --base-url http://127.0.0.1:8100
``` ```
如需同时校验 Web 首页: 如需同时校验 Web 首页:
```bash ```bash
python deploy/linux/smoke_test.py --base-url http://127.0.0.1:8100 --web-url http://127.0.0.1 python3 smoke_test.py --base-url http://127.0.0.1:8100 --web-url http://127.0.0.1
``` ```
### 2. 查看 API 健康状态 ### 4. 诊断包导出
```bash ```bash
curl http://127.0.0.1:8100/health cd /opt/domaincheck/domain-api/deploy/linux
curl http://127.0.0.1:8100/api/v1/runtime/preflight bash collect_diagnostics.sh /opt/domaincheck
``` ```
### 3. 查看 systemd 状态 ## 八、当前发布验收结论
```bash 结合当前 Linux 测试服已经完成的联调结果,可以给出下面的结论:
systemctl status domaincheck-api
systemctl status domaincheck-worker
```
## 七、当前结论
如果以上检查项全部通过,则可以认为:
- Web 管理后台已达到可交付状态 - Web 管理后台已达到可交付状态
- Linux 部署环境已达到可联调状态 - Linux 正式 `systemd` 服务态已验证通过
- 可以进入真实服务器联调或灰度上线阶段 - 核心业务链路已完成最小闭环回归
- 当前剩余工作主要是正式环境发布、灰度观察和持续稳定性观察
一句话结论:
> 当前项目已经通过 Web/Linux 发布所需的核心验收项,后续重点不再是功能开发,而是正式环境收口与上线后观察。

View File

@@ -120,3 +120,10 @@ python deploy/linux/smoke_test.py --base-url http://127.0.0.1:8100
- Linux 实机联调 - Linux 实机联调
- 上线前复测 - 上线前复测
- 真实服务器灰度验证 - 真实服务器灰度验证
如果当前已经进入“海外单脑控制面 + 多机联调 + 准备发布”阶段,建议改为按下面顺序执行:
1. `docs/25_domainCheck_海外单脑控制面上线收口总表.md`
2. `bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-export`
3. `bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-review`
4. `docs/26_domainCheck_发布前运行验证与交付模板.md`

View File

@@ -2,7 +2,7 @@
## 一、用途 ## 一、用途
用于在 Windows 本地把当前可交付内容整理成一份压缩包,便于: 用于在 Windows 或 Linux 上把当前可交付内容整理成一份发布包,便于:
- 发给运维或部署同事 - 发给运维或部署同事
- 存档版本快照 - 存档版本快照
@@ -16,31 +16,60 @@
- `verify_domain_release.ps1` - `verify_domain_release.ps1`
- `prepare_final_release.ps1` - `prepare_final_release.ps1`
- `show_latest_release.ps1` - `show_latest_release.ps1`
- `package_domain_release.sh`
- `verify_domain_release.sh`
- `prepare_final_release.sh`
- `show_latest_release.sh`
执行方式: Windows 执行方式:
```powershell ```powershell
powershell -ExecutionPolicy Bypass -File .\package_domain_release.ps1 powershell -ExecutionPolicy Bypass -File .\package_domain_release.ps1
``` ```
Linux / 海外主机执行方式:
```bash
bash ./package_domain_release.sh
```
如需一键完成“打包 + 验包 + 生成最终准备报告”: 如需一键完成“打包 + 验包 + 生成最终准备报告”:
```powershell ```powershell
powershell -ExecutionPolicy Bypass -File .\prepare_final_release.ps1 powershell -ExecutionPolicy Bypass -File .\prepare_final_release.ps1
``` ```
```bash
bash ./prepare_final_release.sh
```
如需快速查看当前最新交付物: 如需快速查看当前最新交付物:
```powershell ```powershell
powershell -ExecutionPolicy Bypass -File .\show_latest_release.ps1 powershell -ExecutionPolicy Bypass -File .\show_latest_release.ps1
``` ```
```bash
bash ./show_latest_release.sh
```
注意:
- `show_latest_release.*` 现在不只是“显示最近一次 final report 是否存在”
- 它会额外校验 `final_release_report.json` 是否真的对应当前 `latest_release.*`
- 只有 `final_release_report_matches_latest=true` 时,`final_release_ok=true` 才有意义
- `final_release_gate_decision / blocked_reasons / verify_ok / smoke_test_ok` 用于解释“为什么当前能签 / 不能签”
- Ops Center 里的“直接创建 Release / 一键 Worker 灰度 / 一键 Control 发布”
- 现在会硬性依赖 `final_release_ok=true`
- 如果 final report 缺失、过期或门禁未 ready前端会禁用按钮后端接口也会拒绝执行
## 三、输出位置 ## 三、输出位置
打包后会生成: 打包后会生成:
- `release/domaincheck_release_时间戳/` - `release/domaincheck_release_时间戳/`
- `release/domaincheck_release_时间戳.zip` - `release/domaincheck_release_时间戳.zip`
- `release/domaincheck_release_时间戳.tar.gz`
- `release/domaincheck_release_时间戳.sha256.txt` - `release/domaincheck_release_时间戳.sha256.txt`
- `release/latest_release.txt` - `release/latest_release.txt`
- `release/latest_release.json` - `release/latest_release.json`
@@ -50,6 +79,7 @@ powershell -ExecutionPolicy Bypass -File .\show_latest_release.ps1
- `docs/` - `docs/`
- `scripts/` - `scripts/`
- `scripts/` 中会同时带上 PowerShell 和 Shell 版发布脚本
- `domain-api/` - `domain-api/`
- `app` - `app`
- `deploy` - `deploy`
@@ -89,6 +119,10 @@ powershell -ExecutionPolicy Bypass -File .\show_latest_release.ps1
powershell -ExecutionPolicy Bypass -File .\verify_domain_release.ps1 powershell -ExecutionPolicy Bypass -File .\verify_domain_release.ps1
``` ```
```bash
bash ./verify_domain_release.sh
```
5. Windows 联调先跑 `scripts/smoke_test_stack.ps1` 5. Windows 联调先跑 `scripts/smoke_test_stack.ps1`
6. Linux 部署前阅读: 6. Linux 部署前阅读:
- `docs/05_domainCheck_Linux部署清单.md` - `docs/05_domainCheck_Linux部署清单.md`
@@ -106,6 +140,18 @@ powershell -ExecutionPolicy Bypass -File .\verify_domain_release.ps1
这样更适合交付、存档和迁移。 这样更适合交付、存档和迁移。
Windows 默认产物为 `.zip`Linux 默认产物为 `.tar.gz`;两者都会生成同结构的 `release_manifest.json / .sha256.txt / latest_release.*`,便于海外控制面统一管理。
`latest_release.txt / latest_release.json` 用于快速定位“当前最新一份交付包”,避免人工翻目录。 `latest_release.txt / latest_release.json` 用于快速定位“当前最新一份交付包”,避免人工翻目录。
若打包目录本身是 Git 仓库,脚本还会自动写入 `commit_sha / commit_ref`;海外控制面在创建 Release 时可以直接回填提交号,减少人工抄写出错。
`final_release_report.json` 用于记录最近一次“打包 + 验包”的最终状态。 `final_release_report.json` 用于记录最近一次“打包 + 验包”的最终状态。
`show_latest_release.*` 读取这个报告时,还会校验:
- `package_name`
- `archive_path` / `zip_path`
- `sha256`
也就是说,即使目录里留着一份旧的 `final_release_report.json`,只要它不是给当前最新包签出的,`final_release_ok` 也不会误报为 `true`

View File

@@ -55,13 +55,22 @@
- 上线前灰度发布 - 上线前灰度发布
- 发布后观察期 - 发布后观察期
补充说明:
- Linux 测试服基础联调已完成
- 正式 `systemd` 服务态已验证通过
- 当前进入的是“正式上线前最后检查与观察”阶段
## 五、建议下一步 ## 五、建议下一步
1. 把最新交付包发送到目标 Linux 服务器 1. 把最新交付包发送到目标 Linux 服务器
2.`docs/05``docs/07``docs/08` 的顺序执行部署与验收 2.`docs/05``docs/13``docs/14` 的顺序执行部署、核对与收口
3. 部署完成后再做一次真实环境 smoke test 3. 如果当前已经进入海外单脑控制面阶段,再按 `docs/25` 执行统一收口
4. 进入灰度上线 4. `docs/26` 完成发布前运行验证、证据导出与最终交付结论
5. 部署完成后再做一次正式服务态 `smoke test`
6. 导出一份最终诊断包
7. 进入灰度上线
## 六、最终判断 ## 六、最终判断
当前这套项目,已经达到“工程交付完成,待真实环境上线联调”的状态。 当前这套项目,已经达到“工程交付完成,Linux 测试服联调闭环,待正式环境上线收口”的状态。

View File

@@ -16,6 +16,75 @@
- `docs/11_domainCheck_Linux联调输入清单.md` - `docs/11_domainCheck_Linux联调输入清单.md`
### 4. Linux 测试服交接文档
- `docs/13_domainCheck_Linux测试服交接文档.md`
### 5. 正式上线前最终检查单
- `docs/14_domainCheck_正式上线前最终检查单.md`
### 6. 多机检测与跨地域部署设计
- `docs/16_domainCheck_多机检测与跨地域部署设计.md`
### 7. 全流程部署实操手册
- `docs/17_domainCheck_全流程部署实操手册.md`
### 8. CentOS9 一键复制部署与更新文档
- `docs/18_domainCheck_CentOS9一键复制部署与更新文档.md`
### 9. 临时海外控制面联调清单
- `docs/20_domainCheck_临时海外控制面联调清单.md`
### 10. 海外主机集中运维与自动化方案
- `docs/21_domainCheck_海外主机集中运维与自动化方案.md`
### 11. 海外控制面统一入口
- `domain-api/deploy/multi-region/drive_ops_center.sh`
- `domain-api/deploy/multi-region/export_go_live_bundle.sh`
- `domain-api/deploy/multi-region/check_env_drift.sh`
- `domain-api/deploy/multi-region/drive_release_hub.sh`
- `domain-api/deploy/multi-region/drive_ops_action.sh`
- `domain-api/deploy/multi-region/init_ops_center_config.sh`
- `domain-api/deploy/multi-region/check_ops_center_stack.sh`
- `domain-api/deploy/multi-region/check_ops_contracts.sh`
### 12. 海外 Codex 驾驶员与 Ops Center 落地路线
- `docs/22_domainCheck_海外Codex驾驶员与OpsCenter落地路线.md`
### 13. 终局运维架构设计:海外单脑控制面
- `docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md`
### 14. Node Agent 协议与 Release Hub 设计
- `docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md`
### 15. 运维 Contract Schema
- `docs/schemas/ops_agent_protocol.md`
- `docs/schemas/release_hub_contract.md`
- `docs/schemas/ops_driver_contract.md`
- `docs/schemas/ops_job_contract.md`
- `docs/schemas/ops_playbook_contract.md`
- `docs/schemas/ops_observability_contract.md`
- `docs/schemas/ops_stack_diagnosis_contract.md`
### 16. 海外单脑控制面上线收口总表
- `docs/25_domainCheck_海外单脑控制面上线收口总表.md`
### 17. 发布前运行验证与交付模板
- `docs/26_domainCheck_发布前运行验证与交付模板.md`
## 二、文档阅读顺序 ## 二、文档阅读顺序
### 1. 先看总体方案 ### 1. 先看总体方案
@@ -28,6 +97,25 @@
- `docs/05_domainCheck_Linux部署清单.md` - `docs/05_domainCheck_Linux部署清单.md`
- `docs/07_domainCheck_WebLinux发布验收清单.md` - `docs/07_domainCheck_WebLinux发布验收清单.md`
- `docs/09_domainCheck_交付打包说明.md` - `docs/09_domainCheck_交付打包说明.md`
- `docs/13_domainCheck_Linux测试服交接文档.md`
- `docs/14_domainCheck_正式上线前最终检查单.md`
- `docs/16_domainCheck_多机检测与跨地域部署设计.md`
- `docs/17_domainCheck_全流程部署实操手册.md`
- `docs/18_domainCheck_CentOS9一键复制部署与更新文档.md`
- `docs/20_domainCheck_临时海外控制面联调清单.md`
- `docs/21_domainCheck_海外主机集中运维与自动化方案.md`
- `docs/22_domainCheck_海外Codex驾驶员与OpsCenter落地路线.md`
- `docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md`
- `docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md`
- `docs/25_domainCheck_海外单脑控制面上线收口总表.md`
- `docs/26_domainCheck_发布前运行验证与交付模板.md`
- `docs/schemas/ops_agent_protocol.md`
- `docs/schemas/release_hub_contract.md`
- `docs/schemas/ops_driver_contract.md`
- `docs/schemas/ops_job_contract.md`
- `docs/schemas/ops_playbook_contract.md`
- `docs/schemas/ops_observability_contract.md`
- `docs/schemas/ops_stack_diagnosis_contract.md`
### 3. 如果要回溯历史需求与问题 ### 3. 如果要回溯历史需求与问题
@@ -58,6 +146,14 @@
- `domain-api/deploy/systemd/domain-api.service` - `domain-api/deploy/systemd/domain-api.service`
- `domain-api/deploy/systemd/domain-worker.service` - `domain-api/deploy/systemd/domain-worker.service`
- `domain-api/deploy/linux/README.md` - `domain-api/deploy/linux/README.md`
- `domain-api/deploy/multi-region/README.md`
- `domain-api/deploy/multi-region/drive_ops_center.sh`
- `domain-api/deploy/multi-region/drive_release_hub.sh`
- `domain-api/deploy/multi-region/drive_ops_action.sh`
- `domain-api/deploy/multi-region/check_ops_contracts.sh`
- `domain-api/deploy/multi-region/init_ops_center_config.sh`
- `domain-api/deploy/multi-region/bootstrap_overseas.sh`
- `domain-api/deploy/multi-region/bootstrap_mainland.sh`
- `domain-api/deploy/linux/smoke_test.py` - `domain-api/deploy/linux/smoke_test.py`
- `domain-api/deploy/linux/collect_diagnostics.sh` - `domain-api/deploy/linux/collect_diagnostics.sh`
@@ -76,6 +172,8 @@
- 配置迁移与备份 - 配置迁移与备份
- 打包与验包 - 打包与验包
- 最终发布准备 - 最终发布准备
- 海外单脑控制面协议收口
- Ops Center / Codex / CLI 驾驶 contract 收口
剩余工作只在真实 Linux 环境: 剩余工作只在真实 Linux 环境:

View File

@@ -0,0 +1,431 @@
# 13 domainCheck Linux 测试服交接文档
## 一、文档目的
本文档用于把当前 `domainCheck` 项目的 Linux 测试服联调状态,完整交接给后续接手的开发、运维或 Linux 上的 Codex。
目标是回答 4 个问题:
1. 当前到底完成到了什么程度
2. 这次 Linux 测试服已经验证通过了哪些内容
3. 还有哪些事情没有做完
4. 后续继续收口时,应该按什么顺序做
## 二、当前结论
当前项目状态可以明确分成两部分:
### 1. 已完成
- 本地 Windows 开发与联调已完成
- `domain-api``domain-web` 已完成主要功能开发
- Web/API 本地整栈自测已通过
- 交付包、验包、SHA256、最新交付指针已完成
- Linux 测试服数据库初始化问题已定位并修复
- Linux 测试服在“临时 API 进程 + 已初始化数据库”的模式下,`smoke test` 已通过
- Linux 测试服已经完成正式 `systemd` 服务化联调,`domaincheck-api``domaincheck-worker` 均已拉起
- 正式服务态下 `/health` 已确认 `worker_mode = linux-systemd`
- 正式服务态 `smoke test` 已通过
- 已补做一轮真实导入回归,确认“导入域名 -> 写入 `domains` -> 自动创建 `detect_tasks`”链路正常
### 2. 未完全完成
- Linux 测试服虽然已完成正式服务化联调,但仍属于“测试服验证通过”,不等于生产观察期已经完成
- Worker 当前通过 `QT_QPA_PLATFORM=offscreen` 运行,属于“无头 Qt 托管态”,后续仍建议继续观察稳定性
- 真实业务网络环境下的长时检测、代理池质量、Wayback 首次全量列表耗时,还需要继续压测和观察
- 当前数据库里仅导入了少量回归样本,不代表真实大批量数据已完成验收
一句话结论:
> 功能、数据库和正式服务化都已经打通;后续工作转入真实业务回归、稳定性观察和上线前优化。
## 三、这次 Linux 测试服已验证通过的内容
### 1. 数据库初始化问题已确认根因
本次 Linux 测试服最初失败的根因是:
- PostgreSQL 可连接
- 但业务库是空库
- 缺少 `domains` 等核心表
- 导致这些 API 因 `psycopg2.errors.UndefinedTable` 直接 `500`
受影响接口至少包括:
- `/api/v1/dashboard/overview`
- `/api/v1/detect/status`
- `/api/v1/imports/summary`
### 2. 正确修复方式已确认
在 Linux 测试服执行:
```bash
cd /www/wwwroot/getDomain/domainCheck
python init_database.py
```
执行后,核心业务表已成功创建/补齐:
- `domains`
- `detect_tasks`
- `domain_blacklist`
- `sensitive_words`
- `domain_detections`
数据库核查结果为:
- `table_count = 5`
- `domains_count = 0`
说明:
- 库结构已正常
- 只是当前还没有正式业务数据导入
### 3. 临时验证态 smoke test 已通过
新版 `smoke test` 结果:
```json
{
"ok": true
}
```
这说明在当前测试服条件下:
- API 主服务逻辑可用
- PostgreSQL 连接可用
- Redis 连接可用
- 缺表问题已解除
### 4. 临时验证态诊断包已导出
本次测试服诊断产物:
- 目录:`/www/wwwroot/getDomain/diagnostics/diag_20260416_133701`
- 压缩包:`/www/wwwroot/getDomain/diagnostics/diag_20260416_133701.tar.gz`
可用于后续继续排障或归档。
## 四、正式服务态已补验证通过
在后续继续收口过程中,已经额外完成了正式 `systemd` 服务态验证,结果如下:
### 1. 正式服务已落地
已安装并启用:
- `domaincheck-api`
- `domaincheck-worker`
并已确认两者为 `active (running)`
### 2. 运行模式已切换成功
正式服务态下接口返回已确认:
- `/health``worker_mode = linux-systemd`
- `/api/v1/runtime/preflight``worker_mode = linux-systemd`
- `/api/v1/runtime/status` 中:
- `api.service_name = domaincheck-api`
- `worker.service_name = domaincheck-worker`
- `worker.running = true`
- `process_count = 1`
### 3. 正式服务态 smoke test 已通过
正式服务态下再次执行:
```bash
python smoke_test.py --base-url http://127.0.0.1:8100
```
结果仍为:
```json
{
"ok": true
}
```
### 4. 正式服务态诊断包已导出
正式服务态诊断产物:
- 目录:`/opt/domaincheck/diagnostics/diag_20260416_134923`
- 压缩包:`/opt/domaincheck/diagnostics/diag_20260416_134923.tar.gz`
### 5. 正式服务态中已确认的兼容与权限问题
本轮继续联调还确认并处理了两类真实 Linux 问题:
- `detect/jucha.py``detect/juming.py` 中存在 Windows 专属 `subprocess.STARTUPINFO()` 写法,已改为跨平台兼容处理
- 若曾以 `root` 手工运行过 API/Worker可能会留下 `root` 所有者的运行文件,导致正式 `systemd` 服务用户无法写入
其中已实际踩到并修复的权限点包括:
- `domain-api/runtime/` 目录权限
- `domainCheck/detect_worker.log` 文件权限
这个问题的表现是:
- `/api/v1/imports/upload` 因无法创建 `runtime/imports/` 返回 `500`
- Worker 因无法写 `detect_worker.log` 进入循环重启
### 6. 运行中心控制链路已补通
本轮继续验证后,运行中心里的 Linux 控制动作也已经打通:
- Worker `start` / `stop` 已可通过 `sudo -n systemctl` 正常执行
- API 自重启已改为 `systemctl --no-block restart domaincheck-api`
这样处理后,`systemd` 会异步接管重启流程,接口可以先返回成功,避免出现“服务其实已经重启成功,但调用方因为等待自身停机而收到 `500`”的误导性现象。
### 7. 服务态日志噪音已进一步收敛
本轮还额外处理了两类不会阻断功能、但会影响正式服务观察体验的日志噪音:
- Redis 配置订阅从阻塞 `listen()` 改为短轮询 `get_message()`Linux 空闲时不再每分钟刷 `Redis订阅失败: Timeout reading from socket`
- `offscreen` 模式下去掉 Qt 不支持的按钮样式属性Worker 启动时不再刷 `Unknown property transition/transform/box-shadow`
- Worker 图标资源定位改为优先使用 `detect_worker.py` 同目录Linux 服务态不再误报 `/opt/new_logo.svg``/opt/favicon2.ico` 不存在
- 付费检测器改为按需初始化,默认关闭 `detect_jucha` / `detect_juziseo` 时,不再在启动阶段报 cookie 文件缺失
- Redis 未加载 Bloom 模块时保留为降级说明,继续使用普通缓存,不再作为故障级告警处理
这几项修改的结果是:
- `domaincheck-worker` 仍保持 `active (running)`
- `/api/v1/runtime/status``worker.running = true`
- 正式测试服日志更适合持续观察和上线前留档
## 五、这次联调后已经明确固化的部署规则
后续无论谁再部署到 Linux新环境都必须遵守下面这条
> 如果 PostgreSQL 使用的是新库,必须先执行 `domainCheck/init_database.py` 初始化数据库结构。
否则至少这些接口会直接失败:
- `/api/v1/dashboard/overview`
- `/api/v1/detect/status`
- `/api/v1/imports/summary`
这个规则已经同步补入:
- [05_domainCheck_Linux部署清单.md](./05_domainCheck_Linux部署清单.md)
- [domain-api/deploy/linux/README.md](../domain-api/deploy/linux/README.md)
## 六、当前已完成项清单
以下内容可以视为“已经完成”:
### 1. 代码与仓库层
- `domainCheck` 已并入外层总仓库,不再是子模块指针
- 根目录总 `README.md` 已补齐
- `.gitignore` 已补强
- 本地敏感文件、cookies、本地 Node runtime 已从 git 中移除
### 2. Web/API 层
- `domain-web` 主要页面已完成
- `domain-api` 主要接口已完成
- 运行中心、系统设置、导入、导出、日志诊断、自检、自测均已具备
- 正式 `systemd` 服务态下 `/health``/runtime/preflight``/runtime/status``smoke test` 已全部通过
### 3. 交付层
- 交付包已生成
- SHA256 校验已生成
- 验包脚本可用
- 发布准备报告可用
- 最新交付指针可用
### 4. Linux 文档层
- Linux 部署清单已完成
- Linux 诊断采集脚本已完成
- Linux 联调输入清单已完成
- 导航索引文档已完成
### 5. 真实业务回归层
- 已通过 API 上传样本 TXT
- 已确认导入结果:
- 总数 `5`
- 有效 `3`
- 新增 `3`
- 无效 `2`
- 已确认 `domains_total = 3`
- 已确认 `detect_tasks_total = 3`
- 已确认导入后会自动创建 `detect_tasks`
## 七、当前未完成项清单
以下内容仍属于“后续要做”:
### 1. Worker 真实联动验证
还应继续确认:
- Worker 在线状态
- Worker 进程数
- 检测控制页读取是否正常
- `detect_worker.log` 是否正常写入
### 2. 导入更多真实数据后的业务复测
当前已经完成一轮小样本回归,不再是空库空表态。
后续应至少补一次真实业务复测:
- 导入更接近真实业务规模的域名样本
- 查看 `domains` 持续增长
- 查看 `detect_tasks` 持续生成
- 再验证筛选与导出
### 3. 长时间运行与代理池观察
仍建议继续验证:
- Worker 长时运行稳定性
- Redis 订阅超时后的重连是否持续稳定
- 国内网络环境下代理池真实可用率
- Wayback 首次全量快照列表的耗时表现
## 八、后续继续收口的推荐顺序
建议 Linux 上的下一位接手人严格按下面顺序执行。
### 第一步:确认目录完整
确认至少存在:
- `/opt/domaincheck/domainCheck`
- `/opt/domaincheck/domain-api`
- `/opt/domaincheck/domain-web`
### 第二步:确认数据库结构
如果是新库,先执行:
```bash
cd /opt/domaincheck/domainCheck
python3 init_database.py
```
然后确认:
```sql
select tablename
from pg_tables
where schemaname = 'public'
order by tablename;
```
### 第三步:落 systemd
使用这些模板:
- `domain-api/deploy/systemd/domain-api.service`
- `domain-api/deploy/systemd/domain-worker.service`
如果此前用 `root` 手工跑过 API 或 Worker建议先确认下面这些路径对正式服务用户可写
- `domain-api/runtime/`
- `domainCheck/detect_worker.log`
### 第四步:启动正式服务
```bash
sudo systemctl daemon-reload
sudo systemctl enable domaincheck-api
sudo systemctl enable domaincheck-worker
sudo systemctl start domaincheck-api
sudo systemctl start domaincheck-worker
```
### 第五步:检查服务状态
```bash
systemctl status domaincheck-api --no-pager -l
systemctl status domaincheck-worker --no-pager -l
journalctl -u domaincheck-api -n 200 --no-pager
journalctl -u domaincheck-worker -n 200 --no-pager
```
### 第六步:检查 API 状态
```bash
curl http://127.0.0.1:8100/health
curl http://127.0.0.1:8100/api/v1/runtime/preflight
curl http://127.0.0.1:8100/api/v1/runtime/status
```
### 第七步:做一轮导入回归
至少验证:
- `/api/v1/imports/upload`
- `/api/v1/imports/tasks`
- `/api/v1/imports/summary`
- `domains` 增长
- `detect_tasks` 自动创建
目标是确认:
- `status = ok`
- `worker_mode = linux-systemd`
### 第七步:运行 smoke test
```bash
cd /opt/domaincheck/domain-api/deploy/linux
python3 smoke_test.py --base-url http://127.0.0.1:8100
```
### 第八步:如异常则导出诊断包
```bash
cd /opt/domaincheck/domain-api/deploy/linux
bash collect_diagnostics.sh /opt/domaincheck
```
## 九、后续交接给 Linux 上 Codex 时,最该提供的材料
如果后续换一位 Linux 上的 Codex 接手,优先给他这些:
### 1. 当前关键结论
- 当前最大已修复问题:数据库未初始化
- 当前最大未收口问题:正式 `systemd` 服务态还没完全落定
### 2. 当前最关键文件
- `domainCheck/.env`
- `api_health_curl.txt`
- `api_preflight_curl.txt`
- `api_runtime_curl.txt`
- 诊断包:
- `diag_20260416_133701.tar.gz`
### 3. 必看文档
- [12_domainCheck_导航索引.md](./12_domainCheck_导航索引.md)
- [11_domainCheck_Linux联调输入清单.md](./11_domainCheck_Linux联调输入清单.md)
- [05_domainCheck_Linux部署清单.md](./05_domainCheck_Linux部署清单.md)
- [08_domainCheck_交付说明.md](./08_domainCheck_交付说明.md)
## 十、最终交接结论
当前项目不再是“开发未完成”,而是:
> 开发已完成Linux 测试服联调已完成第一轮关键打通,剩余工作集中在正式服务化部署与上线前最后复测。
因此,对下一位接手者的要求不是“继续开发功能”,而是:
- 完成正式 Linux 服务落地
- 跑正式服务态 smoke test
- 如有异常,基于诊断包继续排障
- 最终完成上线前收口

View File

@@ -0,0 +1,278 @@
# 14 domainCheck 正式上线前最终检查单
## 一、使用场景
本文档用于正式上线前最后一次收口。
适用前提:
- 代码已更新到最新版本
- Linux 测试服已完成基础联调
- PostgreSQL 已执行过 `domainCheck/init_database.py`
- `domaincheck-api``domaincheck-worker` 已按 `systemd` 托管
如果当前仍处于“新机器首次部署”,请先回看:
- `docs/05_domainCheck_Linux部署清单.md`
- `domain-api/deploy/linux/README.md`
- `docs/13_domainCheck_Linux测试服交接文档.md`
如果后续进入“国外控制面 + 大陆执行面 + 多 Worker 扩容”阶段,请直接补充阅读:
- `docs/16_domainCheck_多机检测与跨地域部署设计.md`
- `domain-api/deploy/multi-region/README.md`
如果当前已经进入“大陆 controller + 海外 control”双地域正式联调还应额外确认
- 大陆 `controller` 节点的 `/etc/default/domaincheck-worker`
- `NODE_ROLE=control`
- 大陆 `domaincheck-sync-agent`
- 已启动并稳定运行
- 海外控制面 `runtime/sync-summary`
- 能看到 `detect_result_batches`
如果当前已经切到“海外单脑控制面统一驾驶”模式,建议同时配套阅读:
- `docs/25_domainCheck_海外单脑控制面上线收口总表.md`
- `docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md`
- `docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md`
## 二、上线前必须确认的结论
上线前至少要确认下面这些结论同时成立:
- `domaincheck-api``active (running)`
- `domaincheck-worker``active (running)`
- `/health` 返回 `worker_mode=linux-systemd`
- `/api/v1/runtime/preflight` 返回 `ok=true`
- `smoke test` 返回 `ok=true`
- 运行中心里的 `start_worker / stop_worker / restart_api` 控制链路可用
- 导入、筛选、批量更新、导出四条核心业务链路至少各回归一次
- 诊断包可正常导出
## 三、正式上线前执行顺序
### 0. 先跑一遍统一上线总检
如果当前已经进入“海外单脑控制面 + 多地域 / Node Agent”这条正式链路建议先跑
```bash
cd /www/wwwroot/getDomain/domain-api
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-check http://127.0.0.1:8100 http://152.53.37.118:8100 summary
```
期望:
- `go_live_status``ready` 或至少没有新的 `blocking_reasons`
- `stack_status` 不为 `blocked`
- `route_surface_complete=true`
- `launchpad_status` 不为 `blocked`
- 如果当前已经纳管执行节点,则 `remote_access_ready` 不应长期为 `0`
- `next_step_action_code` / `operator_title` 应能直接说明当前第一优先动作
- 如果 `log_sync_enabled=true`,则要额外看 `log_sync_state``log_sync_covered_nodes`
如果这里已经出现 `bootstrap_run / run_acceptance`,说明当前上线前仍有节点接管缺口,应先收口首个缺口节点,再继续下面的业务核验。
建议这样理解总检输出:
- `blocking_reasons` 只放真正会阻断上线的项,例如 `remote_agent_ready=0`
- `warnings` 表示还能继续联调,但现在还不适合直接宣称“全部收口”
- `recommended_commands.next_step` 就是当前最值得优先执行的一条命令
- `recommended_commands.log_sync_logs` / `recommended_commands.log_sync_inspection` 用来补远端参与节点的日志观测
### 1. 核对服务状态
```bash
systemctl status domaincheck-api --no-pager -l
systemctl status domaincheck-worker --no-pager -l
```
期望:
- 两个服务都为 `active (running)`
- `domaincheck-worker` 不再循环重启
如果当前是大陆 controller 节点,还要补一条:
```bash
systemctl status domaincheck-sync-agent --no-pager -l
```
期望:
- `domaincheck-sync-agent``active (running)`
- 不循环重启
### 2. 核对健康接口
```bash
curl http://127.0.0.1:8100/health
curl http://127.0.0.1:8100/api/v1/runtime/preflight
curl http://127.0.0.1:8100/api/v1/runtime/readiness
curl http://127.0.0.1:8100/api/v1/runtime/status
```
期望:
- `/health` 返回 `status=ok`
- `/health` 返回 `worker_mode=linux-systemd`
- `/runtime/preflight` 返回 `ok=true`
- `/runtime/readiness` 不应返回 `blocking`
- `/runtime/status` 返回 `worker.running=true`
如果当前已经接入跨地域同步,还建议补看:
```bash
curl http://127.0.0.1:8100/api/v1/runtime/sync-summary
```
期望:
- 返回里能看到 `detect_result_batches`
- 至少能区分:
- `synced`
- `projected`
- `failed`
- 若大陆 `sync-agent` 已接上,则最近执行过的检测任务不应长期停留在 `projected`
当前 `runtime/preflight` 还会额外展示:
- RedisBloom 是否安装,若未安装会明确提示“降级为普通缓存”
- `detect_jucha` / `detect_juziseo` 是否启用
- 若启用了付费检测,对应本地 cookie 文件是否已就绪
当前 `detect/status` / `runtime/status` 还会明确展示代理运行态:
- `代理正常`
- `降级直连`
- `等待代理`
解释:
- `降级直连` 表示代理池暂时无可用代理,但当前允许直连兜底,任务不会因此中断
- `等待代理` 表示代理池无可用代理,且当前未允许直连,这会直接影响检测吞吐或导致步骤失败
当前还补充了两类更细的诊断语义:
- `proxy_runtime_reason=supplier_empty_pool`
- 表示代理源最近都返回了正常 HTTP 响应,但原始代理数为 `0`
- 这类问题更偏向供应侧空池,不是程序拉取失败
- `dependency_alerts`
- 表示外部依赖站点当前存在可观测异常
- 例如 `web.archive.org` 拒连、超时、连接池异常等
当前免费检测链路中的外部依赖异常还采用了“降级继续”策略:
- 例如 `时光机 / 站长之家 / 爱站 / 百度 / 360` 这类外部站点出现明显网络波动、拒连、超时
- 系统会优先记录为步骤级 `degraded`
- 并将域名置为 `待人工复核`
- 同时继续执行后续检测步骤,避免把整条任务链路直接污染成 `检测失败`
### 3. 跑正式服务态 smoke test
```bash
cd /opt/domaincheck/domain-api/deploy/linux
python3 smoke_test.py --base-url http://127.0.0.1:8100
```
如需把 Web 首页一起纳入检查:
```bash
python3 smoke_test.py --base-url http://127.0.0.1:8100 --web-url http://127.0.0.1
```
期望:
- 输出中 `ok=true`
### 4. 回归运行中心控制动作
建议至少各执行一次:
- `start_worker`
- `stop_worker`
- `restart_api`
期望:
- `stop_worker` 后,`runtime/status``worker.running=false`
- `start_worker` 后,`runtime/status``worker.running=true`
- `restart_api` 调用返回成功,随后 API 能重新恢复
说明:
- 当前 Linux 正式服务态已改为 `systemctl --no-block restart domaincheck-api`
- 因此 `restart_api` 会先返回成功,再由 `systemd` 异步完成 API 切换
### 5. 回归核心业务链路
建议至少确认下面 4 条:
- 导入域名成功,且会落到 `domains`
- 导入后自动创建 `detect_tasks`
- 筛选接口 `/api/v1/domains` 返回正常
- 批量更新后数据库字段与页面展示一致
- 导出任务可创建、导出文件可下载
如果时间紧,最小回归顺序建议为:
1. 导入一份小样本
2. 查看导入任务结果
3. 查看域名列表
4. 执行一次批量更新
5. 生成一次 TXT 或 CSV 导出
## 四、建议保留的上线证据
正式上线前,建议至少保留下面这些结果:
- `systemctl status domaincheck-api --no-pager -l`
- `systemctl status domaincheck-worker --no-pager -l`
- `journalctl -u domaincheck-api -n 200 --no-pager`
- `journalctl -u domaincheck-worker -n 200 --no-pager`
- `systemctl status domaincheck-sync-agent --no-pager -l`
- `journalctl -u domaincheck-sync-agent -n 200 --no-pager`
- `/health` 返回
- `/api/v1/runtime/preflight` 返回
- `/api/v1/runtime/sync-summary` 返回
- `smoke_test.py` 输出
- 一份最新诊断包
诊断包导出命令:
```bash
cd /opt/domaincheck/domain-api/deploy/linux
bash collect_diagnostics.sh /opt/domaincheck
```
## 五、当前可接受的非阻断项
以下项目目前已确认不会阻断正式服务运行:
- Redis 未安装 Bloom 模块时,会降级为普通缓存
- `worker``QT_QPA_PLATFORM=offscreen` 下无头运行
- 付费检测默认关闭时,不要求本机预置 `jucha` / `juziseo` cookie 文件
这些项可以在后续优化阶段继续增强,但不应再作为当前上线阻塞条件。
## 六、仍建议继续观察的项
以下内容不属于当前功能阻断,但上线后建议继续观察:
- 真实代理池可用率
- 代理为空时是否长期停留在 `降级直连`
- Wayback 首次全量检测耗时
- 长时间运行下的 Worker 稳定性
- 真实业务数据量上升后的数据库与导出耗时
## 七、最终上线判定
如果下面三类检查都通过,就可以视为已经具备正式上线条件:
- 服务状态检查通过
- 核心接口与 `smoke test` 通过
- 核心业务链路回归通过
一句话判定:
> 当前项目已经完成开发、Linux 测试服联调、正式服务态验证和关键日志降噪;剩余工作主要是正式环境发布与上线后观察,不再是功能性大修。

View File

@@ -0,0 +1,59 @@
# domainCheck Web 对齐旧桌面功能核对表
更新时间2026-04-16
## 一、旧桌面主标签页对齐
| 旧桌面标签 | Web 当前状态 | 说明 |
| --- | --- | --- |
| 聚名爬取 | 已补齐 | 已支持聚名账号密码登录、聚查自动联名、过期删除/一口价采集、Cookie 兜底上传 |
| 域名筛选 | 已补齐主干 | 已补“全部”默认选项,支持查询、分页、批量更新、筛选页导出范围,并继续补回旧桌面明细列 |
| 域名导入 | 已补齐主干 | 已支持 TXT 上传导入,也已补回手工粘贴域名创建导入任务 |
| 敏感词配置 | 已补齐 | 本轮新增独立页面,支持加载、编辑、导入、导出、保存 |
| 系统设置 | 已补齐主干 | 已补桔子SEO 登录入口;聚名登录入口放在“聚名采集”页 |
## 二、旧桌面登录能力对齐
| 能力 | Web 当前状态 | 说明 |
| --- | --- | --- |
| 聚名账号密码登录 | 已补齐 | 位于 `#/juming` |
| 聚查联名登录 | 已补齐 | 聚名登录后自动执行,同时提供手动“重新联名登录聚查” |
| 桔子SEO 登录 | 已补齐 | 位于 `#/settings` 的“第三方登录”卡片 |
## 三、已确认补齐的体验项
- 域名筛选下拉框显式提供“全部”
- 桔子SEO 不再遗漏登录入口
- 敏感词配置不再缺页
- 聚查不只依赖自动联名,也可手动重试
- 域名导入已补回“粘贴域名后直接导入”
- 筛选页已补回“当前页 / 导出几页 / 全部”的导出范围能力
- 筛选页已补回旧桌面常用明细列过期时间、单位性质、百度历史、百度Site、中文标题、360 Site、Google Site
- 批量更新已补回上述检测明细字段的人工修正入口
- CSV / Excel 导出已补回旧桌面常用明细列,避免导出结果比桌面版缩水
- 聚名页面已显式展示“已保存账号 / 聚名登录态 / 聚查联名状态”,避免运营误判
- 系统设置页已显式展示“已保存桔子SEO账号 / Cookie 就绪状态”,并同步持久化到本地与 Redis
- 聚名采集、域名导入、检测控制三条长任务链路均已统一为“任务中心”形态,支持阶段态、日志常驻、切页后回看
- 检测控制页已补齐更细的阶段态展示,可识别“准备检测 / 刷新代理池 / 取任务中 / 建线程中 / 检测中 / 批次完成 / 完成归档”
- 检测控制页已补齐阶段切换时间线,便于回看长任务在何时进入哪个阶段
- 聚名采集页已补齐中文状态标签、当前采集阶段与任务概览卡片,避免运营面对英文状态误判
- 域名导入页已补齐“选中文件预估行数”和“当前导入阶段/任务概览”摘要,更接近旧桌面即时反馈体验
- 域名导入页已补齐“前 10 行本地预览”和“大文件任务提示”,降低误传错文件的概率
- 域名导入页已补齐提交前本地预检,可即时展示“有效 / 重复 / 非法”统计
- 域名导入页已补齐“来源类型”选择与任务展示,导入记录可区分 TXT 导入 / 手工录入 / 其它
- 域名筛选页已补齐“单位性质”筛选,进一步对齐旧桌面常用条件
- 域名筛选页已补齐“来源类型”筛选;导入页完成后可一键跳转到筛选页查看对应来源结果
- 聚名采集、域名导入、检测控制三页的任务中心文案已统一,均按“阶段 / 摘要 / 日志 / 回看”同一口径表达
## 四、下一轮继续核对的次级项
- 旧桌面导入页的少量细节交互,是否还需要补更细的批次说明
- 旧桌面检测控制页的少量状态提示文案,是否还需要继续压词统一
- 旧桌面批量筛选中的少量边缘筛选项,是否还有遗漏
## 五、当前可直接验证的页面
- `http://152.53.37.118:3201/#/juming`
- `http://152.53.37.118:3201/#/domains`
- `http://152.53.37.118:3201/#/settings`
- `http://152.53.37.118:3201/#/sensitive-words`

View File

@@ -0,0 +1,796 @@
# 16 domainCheck 多机检测与跨地域部署设计
## 一、目标
本文档用于固化 `domainCheck` 的正式多机落地方案,满足下面这些约束:
- Web 后台、管理 API 必须部署在国外机器
- 检测执行、代理、Redis、运行态存储部署在大陆机器
- 最终结果、配置、归档、备份以国外机器为主
- 初期部署不复杂,支持从 `国外 1 台 + 大陆 1 台` 起步
- 后期不够时,优先横向增加大陆 Worker不推翻整体架构
一句话原则:
> 国外负责“管、看、存、备份”,大陆负责“跑、调度、抢任务、贴近代理资源”。
## 二、当前落地状态
截至 `2026-04-16`,第一阶段多机运行骨架已经完成,当前代码已具备:
- 控制面节点注册与心跳
- 执行面节点注册与心跳
- 运行库骨架表自动初始化
- 集群节点快照接口
- 国外/大陆两套部署脚手架
当前已落地的运行态表:
- `detect_worker_nodes`
- `detect_jobs`
- `detect_job_items`
- `detect_run_events`
- `detect_sync_records`
当前可直接验证的接口:
- `GET /api/v1/runtime/status`
- `GET /api/v1/runtime/readiness`
- `GET /api/v1/runtime/cluster`
- `GET /api/v1/detect/job/active`
- `GET /api/v1/detect/jobs`
- `GET /api/v1/detect/queue-summary`
当前 `runtime/cluster` 还补充了 `summary` 摘要,至少会返回:
- `status_counts`
- `role_counts`
- `region_counts`
- `online_worker_nodes`
- `online_control_nodes`
- `busy_nodes`
- `stale_nodes`
- `offline_nodes`
当前还补充了同步观测骨架:
- `GET /api/v1/runtime/sync-summary`
- `GET /api/v1/runtime/sync-records`
可用于提前观察:
- 当前节点是否启用同步推送
- 源地域 / 目标地域配置是否正确
- `detect_sync_records` 最近状态分布
当前代码还补了一层“运行态自动投影”:
- 控制面在读取 `runtime/status` 时,会把当前运行摘要按去重策略写入 `detect_sync_records`
- 当前记录类型为:
- `runtime_projection`
- 当前还新增了“结果摘要投影”:
- `detect_result_projection`
- 用于把当前活跃任务的摘要、最近阶段事件、任务收敛进度先沉淀到统一同步面板
- 其作用不是替代后续真正的 `sync-service`
- 而是先保证跨地域部署阶段已经有统一可观察的“同步记录面板”
当前还补上了正式同步最小闭环骨架:
- 大陆执行面可通过 `SYNC_TARGET_API_BASE_URL` 指向国外控制面
-`SYNC_PUSH_ENABLED=true`,应由大陆 `domaincheck-sync-agent` 按轮询间隔自动推送最新运行态投影
- 国外控制面通过:
- `POST /api/v1/runtime/sync-ingest`
接收投影
- 若配置了 `SYNC_SHARED_TOKEN`,接收端会校验:
- `X-Domaincheck-Sync-Token`
因此当前虽然还没有完整业务结果同步服务,但“同步协议、发送端、接收端、记录面板、独立同步代理”都已经有了第一版可运行骨架
当前同步骨架已经支持的记录类型包括:
- `runtime_projection`
- `runtime_ingest`
- `detect_result_projection`
- `detect_result_ingest`
- `runtime_push`
当前这一轮还补上了“结果批次同步可观测”能力:
- `GET /api/v1/runtime/sync-summary` 现在会额外返回:
- `detect_result_batches`
- 可直接按最近检测任务查看:
- 是否已生成结果投影
- 是否已推送
- 是否已被目标地域接收
- 最近一次失败原因
- 当前同步策略也已细化为:
- `runtime_projection`
只推最新一条,避免把历史运行态投影整批补传
- `detect_result_projection`
按批次补推,确保检测结果积压可以自动追平
- 大陆 `controller` 的环境模板也已固定为:
- `NODE_ROLE=control`
避免把 controller 误注册成普通 Worker导致运行中心和 sync-agent 承载判断失真
当前这一轮还额外补齐了“检测会话追踪”能力:
- `POST /api/v1/detect/start` 会生成本轮 `cycle_token`
- `cycle_token` 会进入 Worker 控制指令
- Worker 心跳元数据会回写 `cycle_token / job_id / job_code`
- `domain_started / domain_completed / domain_failed` 事件会附带 `cycle_token`
- `GET /api/v1/detect/job/active` 已支持按当前 `cycle_token` 聚合“本轮事件”
当前运行态还补齐了“代理执行语义”:
- 代理可用时显示 `代理正常`
- 代理暂时不可用但允许直连时显示 `降级直连`
- 代理暂时不可用且不允许直连时显示 `等待代理`
- 当代理源全部 `HTTP 200``raw_items=0` 时,会额外标记为“供应池为空”,避免误判成程序异常
当前阶段的准确表述应为:
> 多机运行骨架已经落地,分布式调度与跨地域结果同步进入下一阶段。
截至当前这一轮代码,最小任务闭环也已经接上:
- `POST /api/v1/detect/start` 会先创建 `detect_jobs`
- Worker 会优先从 `detect_job_items` 领取任务
- 运行中心已能显示当前活跃任务摘要
- 节点状态里已能反映 `busy / current_load`
- Worker 已支持小批量领取、任务续租、过期租约回收
- API 控制面节点已支持定时心跳,避免集群视图把控制面误判为离线
- 活跃任务接口已支持节点分布、进度百分比和最近事件回看
- Worker 进程重启后会主动回收当前节点遗留的 `running / claimed` 运行态,避免后台出现“进程已重启但旧任务仍显示运行中”的残影
这意味着后续新增第二台大陆 Worker 时,已经不再是“完全从零设计”的状态,而是可以在现有骨架上继续细化调度策略。
当前最小联调命令也已经固定为:
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/check_cluster.sh http://127.0.0.1:8100
```
这条命令会连续检查:
- `/health`
- `/api/v1/runtime/cluster`
- `/api/v1/detect/status`
- `/api/v1/detect/job/active`
如需单独检查“跨地域同步骨架是否已接上”,建议再补两条:
```bash
curl http://127.0.0.1:8100/api/v1/runtime/sync-summary
curl http://127.0.0.1:8100/api/v1/runtime/sync-records?limit=10
```
如需快速拿到“当前这套多机部署是否已进入可联调 / 待处理 / 阻断”结论,当前也已经固定了:
```bash
curl http://127.0.0.1:8100/api/v1/runtime/readiness
```
该接口会直接给出:
- `status`
- `ready`
- `attention`
- `blocking`
- `summary`
- `blocking_issues`
- `warnings`
- `info`
如果这两条接口已经能看到:
- `source_region / target_region`
- `records_total > 0`
- 最近记录里出现 `runtime_projection`
则说明当前测试服已经具备:
- 同步配置观测入口
- 同步记录落库入口
- 后续接入正式 `sync-service` 的最小运行骨架
如果要在大陆 controller 节点本机确认“这台机器本身是否配成了 controller而不是普通 Worker”当前也已经固定了一条本机检查命令
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/check_mainland_controller.sh
```
这条命令会直接校验:
- `/etc/default/domaincheck-worker`
- `NODE_ROLE=control`
- `SYNC_PUSH_ENABLED=true`
- `SYNC_TARGET_API_BASE_URL` 是否已填写
- `domaincheck-worker`
- `domaincheck-sync-agent`
是否已经启动
如果当前客观条件下还不能把代码真正部署到大陆机器,当前也支持先在国外测试机上做“模拟多节点联调”:
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/simulate_multi_region.sh http://127.0.0.1:8100
```
这条命令会临时模拟:
- 一个大陆 `controller`
- 一个大陆 `worker`
它的目的不是替代真实部署,而是先把下面这些提前跑通:
- `runtime/readiness`
- `runtime/cluster`
- 运行中心的多机就绪度提示
- 文档、脚本、状态面板三者是否一致
如果测试服之前已经跑过旧节点、旧 worker当前还残留陈旧心跳记录也可以先清一次 `detect_worker_nodes` 里的历史残影,再观察 readiness
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30 --dry-run
bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30
```
它的作用是:
- 清掉很久没心跳的旧节点记录
- 避免运行中心长期被历史离线节点污染成 `attention`
- 让单机模拟多节点联调时,看到更接近真实接入后的状态
## 三点五、当前实测结论
截至 `2026-04-16 18:56`,测试服已经验证通过:
- `domaincheck-api``domaincheck-worker` 可在 `systemd` 下稳定重启
- `worker_mode=linux-systemd`
- `runtime/cluster` 可同时看到:
- `overseas-control-01`
- `mainland-worker-01`
- 大陆 Worker 节点元数据已显示:
- `phase`
- `detail`
- `job_id`
- `job_code`
- `cycle_token`
- `detect/job/active``current_cycle_events` 已只回看当前这一轮检测事件,不再混入旧轮次历史
当前测试服最新一轮实测 `cycle_token` 示例:
- `aec105737f`
该轮已确认能看到:
- `job_dispatch_requested`
- `job_dispatch_sent`
- `domain_started`
- `domain_completed`
这说明“控制面发起一次检测”到“执行面逐域名回写事件”的会话闭环已经打通。
也说明当前后台已经不再只会显示“有告警”,而是能明确说明任务到底是在正常代理、降级直连,还是被代理卡住。
## 四、推荐架构
### 1. 国外控制面
国外机器负责:
- `domain-web`
- `domain-api`
- 国外主 PostgreSQL
- 配置中心
- 导出、审核、运营后台
- 最终结果归档
- 国外备份与日志归档
国外控制面的职责:
- 对外提供访问入口
- 保存最终业务结果
- 保存系统配置和审计记录
- 接收大陆执行面的结果同步
- 为后续灾备提供稳定的权威数据源
### 2. 大陆执行面
大陆机器负责:
- `detect-worker`
- 大陆 Redis
- 大陆运行库 PostgreSQL
- 代理池配置与网络环境
- 本地运行日志
- 调度和任务租约
大陆执行面的职责:
- 抢任务
- 续租
- 运行检测链路
- 写入本地运行态
- 汇总并同步结果到国外
### 3. 初期物理部署
当前最优起步方案:
- 国外 `1` 台:
- `domain-web`
- `domain-api`
- `postgresql_main`
- 大陆 `1` 台:
- `redis`
- `postgresql_runtime`
- `scheduler`
- `detect-worker`
说明:
- 这个起步方案的优先目标是先把跨地域职责边界定清楚
- 大陆机器当前可以先把 Redis、运行库、调度和 Worker 放在同一台
- 但逻辑上必须按不同角色设计,避免后续扩容时重新返工
- 各节点身份建议统一通过 `/etc/default/domaincheck-api``/etc/default/domaincheck-worker` 管理,不直接修改 service 文件正文
### 4. 后续扩容
当大陆执行压力不够时,扩容顺序建议为:
1. 新增大陆 Worker 机器
2. 如果 Redis 压力增大,再拆 Redis
3. 如果运行库写入压力增大,再拆运行库
4. 国外主库继续作为最终结果主库,不参与高频任务调度
后续结构示意:
```text
国外
├── web + api + postgresql_main
└── backup / archive
大陆
├── redis + postgresql_runtime + scheduler
├── worker-01
├── worker-02
├── worker-03
└── worker-N
```
## 五、数据分层
### 1. 结果态数据
这类数据保存在国外主库:
- 域名主数据
- 检测最终结果
- 黑名单结论
- 导出记录
- 审核记录
- 系统配置
- 操作审计
特点:
- 最终一致
- 生命周期长
- 提供给后台页面和运营使用
### 2. 运行态数据
这类数据优先保存在大陆执行面:
- 任务领取状态
- 任务租约
- 节点心跳
- 当前阶段
- 实时日志事件
- 重试信息
- 本地暂存结果
特点:
- 高频读写
- 延迟敏感
- 主要服务于 Worker 协作和调度
## 六、任务模型
当前项目还偏向单机 Worker 直接扫描 `domains` 表的模式。正式多机化后,建议改为显式任务模型。
### 1. 核心表建议
建议新增:
- `detect_jobs`
- `detect_job_items`
- `detect_worker_nodes`
- `detect_run_events`
- `detect_sync_records`
### 2. detect_jobs
表示一轮检测任务。
建议字段:
- `id`
- `job_code`
- `source`
- `plan_hash`
- `status`
- `created_at`
- `started_at`
- `finished_at`
- `created_by`
- `remark`
说明:
- `plan_hash` 用于标识本轮检测所使用的规则版本和参数快照
- 一轮任务可以对应大量域名任务项
### 3. detect_job_items
表示单个域名的具体任务项。
建议字段:
- `id`
- `job_id`
- `domain_id`
- `status`
- `claimed_by`
- `claim_token`
- `lease_expires_at`
- `attempt_count`
- `last_error`
- `started_at`
- `finished_at`
- `result_version`
- `updated_at`
建议唯一约束:
- `unique(job_id, domain_id)`
说明:
- 多台 Worker 只抢 `status=pending` 且未被占用或租约已过期的任务
- `claim_token` 用于避免状态回写串单
- `lease_expires_at` 用于机器故障后的任务回收
### 4. detect_worker_nodes
表示 Worker 节点。
建议字段:
- `node_code`
- `region`
- `role`
- `hostname`
- `ip`
- `status`
- `worker_version`
- `last_heartbeat_at`
- `current_load`
- `remark`
说明:
- 后台后续可以直接展示“哪个节点在线、哪个节点在跑、当前负载多少”
### 5. detect_run_events
表示高价值阶段日志。
建议字段:
- `id`
- `job_id`
- `job_item_id`
- `node_code`
- `event_type`
- `level`
- `message`
- `payload_json`
- `created_at`
说明:
- 页面展示优先依赖事件流,不直接硬依赖某一台机器本地日志文件
- 原始大日志仍保留在大陆 Worker 本地
## 七、多机抢任务与去重
### 1. 抢任务方式
推荐使用数据库租约模型:
- Worker 从 `detect_job_items` 中领取一批待处理任务
- 使用 `FOR UPDATE SKIP LOCKED` 或原子更新方式抢占
- 领取后写入:
- `claimed_by`
- `claim_token`
- `lease_expires_at`
### 2. 去重原则
多机环境下,去重不能依赖“约定不重复”,必须依赖数据库约束和租约。
至少保证:
- 同一轮 `job_id` 下,同一域名只出现一条任务项
- 同一任务项同一时刻只允许被一个 `claim_token` 持有
- 回写结果时校验 `claim_token`
### 3. 续租机制
Worker 执行过程中应定期续租:
-`30-60` 秒续租一次
- 续租时更新 `lease_expires_at`
- 如果节点挂掉,租约到期后其他 Worker 可重新领取
当前代码已实现的原则是:
- 任务被领取后进入 `claimed / running`
- 检测步骤执行过程中会持续续租
- 若任务长期未续租且租约过期,会自动回收到 `pending`
这样可以避免:
- 长任务跑到一半租约失效
- Worker 异常退出后任务永远卡死
- 后续多机扩容时出现大量“假占用”
### 4. 失败重试
建议对失败进行分类:
- 网络失败
- 代理失败
- 第三方目标站异常
- 程序逻辑失败
可按类型控制重试次数,不要无限重试。
### 5. 当前代码与目标模型的关系
当前代码里,运行态表和节点心跳已经具备,但主检测流程仍以现有 `domains` / `detect_status` 链路为主。
这意味着:
- 现在已经可以先把“多机可见性”和“节点骨架”跑起来
- 下一步要把“检测入口”从直接扫 `domains`,逐步切到 `detect_jobs + detect_job_items`
- 切换时必须保留旧链路回退能力,避免一次性重写导致现网不稳
## 八、同步策略
### 1. 国外到大陆
同步内容:
- 系统配置
- 检测规则
- 敏感词版本
- 任务创建命令
特点:
- 低频
- 要求可靠
- 可版本化
### 2. 大陆到国外
同步内容:
- 任务进度摘要
- 关键阶段事件
- 最终检测结果
- 黑名单结论
- 归档日志包索引
特点:
- 高频部分只传摘要和关键事件
- 最终结果必须幂等
### 3. 幂等要求
结果同步到国外时,必须支持幂等:
- 同一 `job_item_id` 重复上报不应产生重复结果
- 同一域名同一轮任务只保留最终有效状态
### 4. 推荐同步落地方式
第一阶段不建议直接做数据库双向复制,更推荐独立同步服务:
- 大陆执行面负责写本地运行态
- `sync-service` 负责批量汇总结果与事件
- 国外控制面负责接收、落库、归档
推荐第一阶段同步内容:
- 最终检测结果
- 关键阶段事件
- 失败摘要
- 节点健康摘要
- 配置快照版本
不建议第一阶段同步:
- 全量原始日志
- 高频心跳明细
- 临时抓取中间产物
原因:
- 成本高
- 跨地域网络抖动会放大耦合
- 对运营后台价值不成比例
## 九、部署建议
### 1. 国外机器
目录建议:
```text
/opt/domaincheck
├── domain-api
├── domain-web
└── shared
```
部署角色:
- `web`
- `api`
- `postgresql_main`
### 2. 大陆调度中心
目录建议:
```text
/opt/domaincheck
├── domainCheck
├── runtime-db
├── redis
└── shared
```
部署角色:
- `scheduler`
- `redis`
- `postgresql_runtime`
- `worker`
### 3. 大陆纯 Worker 节点
目录建议:
```text
/opt/domaincheck
├── domainCheck
└── shared
```
部署角色:
- `worker`
### 4. 一键化原则
部署脚本必须满足:
- 新机器只需要少量环境变量
- 不要求现场手工改很多路径
- 国外机和大陆机各自有独立入口脚本
- 后续新增大陆 Worker 节点继续复用同一脚本
### 5. 当前建议的最小部署
当前最适合正式起步的形态:
- 国外 `1` 台:
- `domain-web`
- `domain-api`
- 国外主 PostgreSQL
- 大陆 `1` 台:
- `redis`
- 大陆运行库 PostgreSQL
- `detect-worker`
- 后续可补 `sync-service`
扩容时优先:
1. 新增大陆 Worker
2. 再视压力拆分大陆运行库与 Redis
3. 国外控制面保持稳定,不跟着高频扩缩
## 十、阶段性落地建议
### 第一阶段
先完成:
- 国外控制面部署
- 大陆单机执行面部署
- 节点注册与心跳
- 当前后台继续可用
### 第二阶段
再完成:
- 任务项模型
- 多 Worker 抢任务
- 事件日志流
- 结果异步同步回国外
### 第三阶段
最后完成:
- 大陆多 Worker 横向扩容
- 运行库与调度中心独立拆分
- 国外归档和监控补齐
## 十一、运行与观测建议
多机之后,不能再只靠“登录某台机器 tail 日志”来判断系统状态。
建议分层:
- 大陆 Worker 本地保留完整原始日志
- `detect_run_events` 保存关键阶段事件
- 国外后台优先展示事件流、节点负载和同步状态
- 真排障时再下钻到具体节点原始日志
后台建议优先展示:
- 当前在线节点数
- 每节点最近心跳
- 每节点当前负载
- 当前活跃任务数
- 队列积压与最老待领年龄
- 租约是否过期、是否即将到期
- 近 15 分钟每节点吞吐
- 最近失败摘要
- 最近同步结果
- 最近结果摘要投影
## 十二、下一阶段开发清单
接下来建议按下面顺序继续落地:
1. 后台创建 `detect_jobs / detect_job_items`
2. Worker 实现批量 claim / renew / finish / fail
3. 增加租约超时回收
4. 将检测阶段事件写入 `detect_run_events`
5. 增加 `sync-service`
6. 完成第二台大陆 Worker 接入演练
## 十三、最终建议
对当前项目来说,最优解不是“全部放国外”,也不是“全部放大陆”,而是:
- 国外做控制面和主结果库
- 大陆做执行面和运行态调度
- 先从 `国外 1 台 + 大陆 1 台` 起步
- 后续优先横向增加大陆 Worker
一句话总结:
> 先把职责边界设计对,再让部署简单;后续扩容时只加 Worker不再重构核心架构。

View File

@@ -0,0 +1,734 @@
# 17 domainCheck 手工部署实操手册
## 一、文档目标
这份文档只讲一件事:
> 不依赖一键脚本,完全手工完成部署、更新、排障和扩容。
它不是设计说明,也不是零散检查单,而是给实际部署时直接照着做的“手工操作手册”。
文档边界:
- 这里只讲手工部署
- 不使用 `install_overseas_quick.sh`
- 不使用 `install_mainland_controller_quick.sh`
- 不使用 `install_mainland_worker_quick.sh`
- 如果你想走傻瓜式复制部署,请改看:
- [18_domainCheck_CentOS9一键复制部署与更新文档.md](/www/wwwroot/getDomain/docs/18_domainCheck_CentOS9一键复制部署与更新文档.md:1)
适用场景:
- 先在国外机器完成单机部署与联调
- 后续再扩到“国外控制面 + 大陆执行面”
- 当前暂时无法把代码真正部署到大陆机器时,先在国外机器模拟多节点联调
- 最后再把同样的部署方式复制到其他机器
一句话理解:
> 先把国外主控机部署好,再按同样套路扩第二台、第三台,不靠临场猜。
并发配置补充:
- 系统支持 `默认线程数 + 节点单独覆盖`
- 节点单独覆盖按机器自己的 `NODE_CODE` 命中
- 某台机器没配置覆盖值时,自动回退到默认线程数
## 二、推荐部署形态
### 1. 当前最推荐起步形态
- 国外机器 `1` 台:
- `domain-web`
- `domain-api`
- PostgreSQL
- Redis
- `domaincheck-worker`
- 后续扩容时:
- 新增大陆 `controller`
- 新增大陆 `worker`
说明:
- 因为你当前还不能直接把代码稳定部署到大陆机器,所以第一阶段先把国外机器单机跑稳
- 这台国外机器同时承担:
- 后台
- API
- 数据库
- Redis
- Worker
- 等这套稳定后,再把多机脚本复制到其他机器
### 2. 最终推荐形态
- 国外 `control`
- `domain-web`
- `domain-api`
- 主 PostgreSQL
- 结果归档
- 大陆 `controller`
- Redis
- 运行态 PostgreSQL
- `domaincheck-worker`
- `domaincheck-sync-agent`
- 大陆 `worker`
- `domaincheck-worker`
## 三、服务器准备
### 1. 系统要求
- CentOS Stream 9
- Python `3.11`
- PostgreSQL `14+`
- Redis `6+`
- Nginx
关键说明:
- 这里的 Python 不是“系统自带什么就用什么”
- 必须明确安装 `python3.11`
- 不能只装系统默认 `python3`
- 因为后续部署命令直接使用的是 `python3.11 -m venv .venv`
推荐先执行:
```bash
dnf install -y python3.11 python3.11-devel
python3.11 --version
```
期望输出类似:
```text
Python 3.11.x
```
### 2. 目录约定
统一使用:
```text
/opt/domaincheck
├── domain-api
├── domain-web
└── domainCheck
```
### 3. 当前仓库与运行态关系
如果你像当前测试机一样,用仓库目录做源码源头,也可以用软链接:
```bash
ln -s /www/wwwroot/getDomain/domain-api /opt/domaincheck/domain-api
ln -s /www/wwwroot/getDomain/domain-web /opt/domaincheck/domain-web
ln -s /www/wwwroot/getDomain/domainCheck /opt/domaincheck/domainCheck
```
如果你是完整复制代码到目标机,也可以直接把目录上传到 `/opt/domaincheck/`
## 四、第一阶段:国外单机部署
这一阶段的目标是:
- 后台可访问
- API 正常
- 数据库已初始化
- Worker 可跑
- 运行中心正常
- smoke test 通过
### 1. 拉取代码
当前建议统一走 `git` 管理和更新,不再手工散传目录。
执行口径:
- 这里建议直接使用 `root`
- 不建议使用 `www` 用户执行整套部署命令
- 因为后面还会接着写 `systemd``/etc/default/``/opt/domaincheck/` 和服务启停
第一次部署建议:
```bash
mkdir -p /www/wwwroot
cd /www/wwwroot
git clone 你的仓库地址 getDomain
cd getDomain
git checkout main
git pull origin main
```
然后建立运行目录软链接:
```bash
mkdir -p /opt/domaincheck
ln -s /www/wwwroot/getDomain/domain-api /opt/domaincheck/domain-api
ln -s /www/wwwroot/getDomain/domain-web /opt/domaincheck/domain-web
ln -s /www/wwwroot/getDomain/domainCheck /opt/domaincheck/domainCheck
```
后续更新统一使用:
```bash
cd /www/wwwroot/getDomain
git fetch --all
git checkout main
git pull --ff-only origin main
```
### 1.1 先确认 Python 3.11 已安装
如果当前机器还没有 `python3.11`,先执行:
```bash
dnf install -y python3.11 python3.11-devel
python3.11 --version
```
只有确认 `python3.11` 命令存在后,再继续下面的虚拟环境步骤。
### 2. 创建 Python 虚拟环境
```bash
cd /opt/domaincheck/domainCheck
python3.11 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
python3.11 - <<'PY'
from pathlib import Path
source = Path("requirements.txt")
target = Path("requirements.linux.txt")
raw = source.read_bytes()
for encoding in ("utf-8", "utf-16", "utf-16-le", "utf-16-be", "gbk"):
try:
text = raw.decode(encoding)
break
except UnicodeDecodeError:
continue
else:
raise SystemExit("无法解析 requirements.txt 编码")
skip_prefixes = (
"pywin32==",
"pywin32-ctypes==",
"twisted-iocpsupport==",
"win32-setctime==",
)
lines = []
for line in text.splitlines():
normalized = line.strip().lstrip("\ufeff")
if normalized.lower().startswith(skip_prefixes):
continue
lines.append(normalized)
target.write_text("\n".join(lines) + "\n", encoding="utf-8")
PY
pip install -r requirements.linux.txt
```
然后补 API 依赖:
```bash
cd /opt/domaincheck/domain-api
/opt/domaincheck/domainCheck/.venv/bin/pip install fastapi uvicorn pydantic-settings psycopg2-binary redis openpyxl python-multipart
```
补充说明:
- 这里不能直接在 Linux 上裸跑 `pip install -r requirements.txt`
- 因为桌面版历史依赖里包含 `pywin32` 等 Windows-only 包
- 手工部署时也必须先生成 `requirements.linux.txt` 再安装
### 3. 配置数据库和 Redis
确保 PostgreSQL 和 Redis 可用。
建议先确认:
```bash
psql -h 127.0.0.1 -U postgres -d domain -c "select 1;"
redis-cli ping
```
### 4. 配置 `domainCheck/.env`
至少确认这些项:
```env
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=domain
DB_USER=postgres
DB_PASSWORD=你的密码
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
```
### 5. 初始化数据库
这是最重要的一步,新库必须先做:
```bash
cd /opt/domaincheck/domainCheck
python3 init_database.py
```
如果不先执行,至少这些接口会直接 `500`
- `/api/v1/dashboard/overview`
- `/api/v1/detect/status`
- `/api/v1/imports/summary`
### 6. 构建前端
进入 `domain-web`,配置生产环境 API 地址:
```bash
cd /opt/domaincheck/domain-web
cp .env.production.example .env.production
```
`VITE_API_BASE_URL` 改成目标 API例如
```env
VITE_API_BASE_URL=https://api.domain.com/api/v1
```
然后构建:
```bash
npm install
npm run build
```
### 7. 配置 Nginx
参考:
- `domain-web/deploy/nginx/domain-web.conf`
把静态目录指到:
```text
/opt/domaincheck/domain-web/dist
```
常见做法:
- `admin.domain` 对外提供后台页面
- `api.domain.com` 对外提供 API
### 8. 安装 systemd 服务
复制模板:
```bash
cp /opt/domaincheck/domain-api/deploy/systemd/domain-api.service /etc/systemd/system/domaincheck-api.service
cp /opt/domaincheck/domain-api/deploy/systemd/domain-worker.service /etc/systemd/system/domaincheck-worker.service
```
### 9. 配置 API 环境变量
建议使用:
```bash
cp /opt/domaincheck/domain-api/deploy/multi-region/templates/domaincheck-api.env.example /etc/default/domaincheck-api
```
至少改这些:
```env
WORKER_MODE=linux-systemd
API_HOST=0.0.0.0
API_PORT=8100
DOMAIN_ROOT=/opt/domaincheck/domainCheck
NODE_CODE=overseas-control-01
NODE_REGION=overseas
NODE_ROLE=control
CORS_ORIGINS='["http://127.0.0.1:3201","http://localhost:3201","http://你的服务器IP:3201"]'
SYNC_PUSH_ENABLED=false
```
如果你已经固定域名,建议直接改成:
```env
CORS_ORIGINS='["https://admin.domain","http://127.0.0.1:3201","http://localhost:3201"]'
```
### 10. 修正权限
```bash
mkdir -p /opt/domaincheck/domain-api/runtime
touch /opt/domaincheck/domainCheck/detect_worker.log
chown -R www:www /opt/domaincheck/domain-api/runtime
chown www:www /opt/domaincheck/domainCheck/detect_worker.log
chmod 664 /opt/domaincheck/domainCheck/detect_worker.log
```
### 11. 启动服务
```bash
systemctl daemon-reload
systemctl enable domaincheck-api
systemctl enable domaincheck-worker
systemctl restart domaincheck-api
systemctl restart domaincheck-worker
```
### 12. 检查服务状态
```bash
systemctl status domaincheck-api --no-pager -l
systemctl status domaincheck-worker --no-pager -l
```
## 五、第一阶段验收
### 1. 接口检查
```bash
curl http://127.0.0.1:8100/health
curl http://127.0.0.1:8100/api/v1/runtime/preflight
curl http://127.0.0.1:8100/api/v1/runtime/status
curl http://127.0.0.1:8100/api/v1/runtime/readiness
```
期望:
- `/health.status=ok`
- `/health.worker_mode=linux-systemd`
- `/runtime/preflight.ok=true`
- `/runtime/status.worker.running=true`
- `/runtime/readiness.status` 至少不是 `blocking`
### 2. smoke test
```bash
cd /opt/domaincheck/domain-api/deploy/linux
python3 smoke_test.py --base-url http://127.0.0.1:8100
```
如果要连 Web 一起检查:
```bash
python3 smoke_test.py --base-url http://127.0.0.1:8100 --web-url http://127.0.0.1:3201
```
期望:
- `ok=true`
### 3. 后台页面检查
浏览器打开:
```text
https://admin.domain
```
至少检查:
- 登录
- 运行中心
- 系统设置
- 域名筛选
- 导入
- 导出
## 六、第二阶段:国外机器模拟多机联调
如果你暂时还不能把代码部署到大陆机器,就先在国外机器做这一步。
### 1. 一键多机演练
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/rehearse_multi_region.sh http://127.0.0.1:8100
```
它会自动模拟:
- 一个大陆 controller
- 两个大陆 worker
并自动检查:
- `runtime/readiness`
- `runtime/cluster`
- online control / online worker 数量
- 节点状态是否符合预期
### 2. 通过标准
如果输出里出现:
```text
rehearsal passed
```
说明当前这台国外机器上的多机模拟联调已通过,可以继续部署到其他机器。
### 3. 如果想手工模拟
也可以单独跑:
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/simulate_multi_region.sh http://127.0.0.1:8100
```
停止时按:
```text
Ctrl+C
```
### 4. 清理旧节点残影
如果之前测试过多轮,集群里可能残留老节点:
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30 --dry-run
bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30
```
如果只删某个旧节点:
```bash
bash deploy/multi-region/prune_cluster_nodes.sh --node-code mainland-worker-01
```
## 七、第三阶段:部署到其他机器
等国外单机和模拟多机都通过后,就可以把同样的代码与脚本部署到其他机器。
### A. 新海外控制机
在目标机执行:
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/bootstrap_overseas.sh /opt/domaincheck
```
然后完善:
- `/etc/default/domaincheck-api`
- Nginx
- PostgreSQL
- Redis
最后检查:
```bash
bash deploy/multi-region/check_cluster.sh http://127.0.0.1:8100
```
### B. 大陆 controller
在目标机执行:
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck controller
```
然后检查:
```bash
bash deploy/multi-region/check_mainland_controller.sh
```
关键配置是:
```env
NODE_CODE=mainland-controller-01
NODE_REGION=mainland
NODE_ROLE=control
SYNC_PUSH_ENABLED=true
SYNC_SOURCE_REGION=mainland
SYNC_TARGET_REGION=overseas
SYNC_TARGET_API_BASE_URL=http://海外控制面IP:8100/api/v1
SYNC_SHARED_TOKEN=你自己的共享令牌
```
### C. 大陆 worker
在目标机执行:
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck worker
```
关键配置是:
```env
NODE_CODE=mainland-worker-01
NODE_REGION=mainland
NODE_ROLE=worker
SYNC_PUSH_ENABLED=true
SYNC_SOURCE_REGION=mainland
SYNC_TARGET_REGION=overseas
SYNC_TARGET_API_BASE_URL=http://海外控制面IP:8100/api/v1
```
## 八、部署到其他机器后的联调顺序
建议按这个顺序,不容易乱:
1. 先让海外控制机稳定
2. 再接大陆 controller
3. 再接第一台大陆 worker
4. 再接第二台、第三台 worker
每接一台都执行:
```bash
curl http://海外控制机:8100/api/v1/runtime/readiness
curl http://海外控制机:8100/api/v1/runtime/cluster
curl http://海外控制机:8100/api/v1/runtime/sync-summary
```
如果海外 API 已经挂到正式域名,建议直接写成:
```bash
curl https://api.domain.com/api/v1/runtime/readiness
curl https://api.domain.com/api/v1/runtime/cluster
curl https://api.domain.com/api/v1/runtime/sync-summary
```
### 联调通过标准
- `runtime/cluster` 能看到新节点
- `last_heartbeat_at` 持续刷新
- 大陆 controller 为 `role=control`
- 大陆 worker 为 `role=worker`
- 执行任务时 worker 状态能变成 `busy`
- `runtime/readiness` 至少不是 `blocking`
- `runtime/sync-summary` 能看到 `detect_result_batches`
## 九、上线前最后检查
按这份文档部署完成后,再回看:
- [14_domainCheck_正式上线前最终检查单.md](/www/wwwroot/getDomain/docs/14_domainCheck_正式上线前最终检查单.md:1)
重点保留:
- `systemctl status`
- `journalctl`
- `/health`
- `/runtime/preflight`
- `/runtime/readiness`
- `/runtime/sync-summary`
- `smoke test`
- 诊断包
## 十、常见问题
### 1. API 启动了,但接口 500
优先检查有没有先执行:
```bash
cd /opt/domaincheck/domainCheck
python3 init_database.py
```
### 2. Worker 一直重启
优先检查:
- `/opt/domaincheck/domainCheck/detect_worker.log` 权限
- `/opt/domaincheck/domain-api/runtime/` 权限
- `domainCheck/.env` 数据库和 Redis 配置
### 3. readiness 一直是 `attention`
优先检查:
- 集群里是否残留旧离线节点
- 是否还没接入大陆 controller
- 是否还没有在线 worker
必要时先清理旧节点:
```bash
bash deploy/multi-region/prune_cluster_nodes.sh --minutes 30
```
### 4. 模拟多机通过了,真实机器还没接上
这是正常的。
模拟多机的意义是:
- 验证代码、脚本、页面、状态口径一致
- 不代表真实大陆网络、代理、同步链路已经完成
真实机器接入时,重点要再看:
- 节点心跳
- 同步目标地址
- 共享 token
- 真实 Redis / PostgreSQL 连接
## 十一、最短执行版本
如果你只想看最短版,可以照这个跑:
### 国外单机先跑通
```bash
cd /opt/domaincheck/domainCheck
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python3 init_database.py
cd /opt/domaincheck/domain-api
/opt/domaincheck/domainCheck/.venv/bin/pip install fastapi uvicorn pydantic-settings psycopg2-binary redis openpyxl python-multipart
systemctl daemon-reload
systemctl enable domaincheck-api domaincheck-worker
systemctl restart domaincheck-api domaincheck-worker
curl http://127.0.0.1:8100/health
curl http://127.0.0.1:8100/api/v1/runtime/preflight
curl http://127.0.0.1:8100/api/v1/runtime/readiness
```
### 再跑多机模拟验收
```bash
cd /opt/domaincheck/domain-api
bash deploy/multi-region/rehearse_multi_region.sh http://127.0.0.1:8100
```
### 通过后再上其他机器
```bash
bash deploy/multi-region/bootstrap_overseas.sh /opt/domaincheck
bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck controller
bash deploy/multi-region/bootstrap_mainland.sh /opt/domaincheck worker
```
## 十二、最终结论
当前最稳的推进方式是:
1. 先在国外机器完成单机部署
2. 再在国外机器完成多机模拟演练
3. 演练通过后,再复制到其他机器
4. 最后再做真实跨地域联调
一句话总结:
> 先把单机跑稳,再把多机脚本跑通,最后再扩机器;每一步都有现成脚本,不靠现场猜。

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,404 @@
# domainCheck 国内外联调交接说明
## 1. 当前目标
本次联调的目标是把现有架构整理成下面这条可运行链路:
- 海外机保留主数据与后台展示
- 海外机把待检测任务批次下发到国内 controller
- 国内 controller 落本地任务与本地 `domains`
- 国内 worker 执行检测
- 国内运行时状态、检测结果再同步回海外
- 海外后台统一查看总体进度与结果
当前主链路已经基本跑通,剩下的是:
- 海外 cluster/readiness 视图的最后收尾
- 文档固化
- 最好增加“国内日志回调到海外”的调试手段,减少人工复制日志
---
## 2. 当前已确认跑通的链路
### 2.1 海外 API 正常
海外 API 已经具备:
- `/health`
- `/api/v1/runtime/cluster`
- `/api/v1/runtime/readiness`
- `/api/v1/runtime/preflight`
- `/api/v1/runtime/sync-summary`
并且 nginx 对 `/api/v1/runtime/*` 的转发已经修好。
### 2.2 国内 controller 正常
国内 controller 这边已经确认:
- `domaincheck-api` 正常运行
- `domaincheck-sync-agent` 正常运行
- 本地 PostgreSQL 可用
- 本地 Redis 可用
- `detect/start` 不再受 `sudo: a password is required` 影响
### 2.3 国内 worker 正常
国内 worker 这边已经确认:
- `domaincheck-worker` 正常运行
- 可以连接国内 controller 的 PostgreSQL
- 可以连接国内 controller 的 Redis
- Redis 密码配置后Worker 控制指令已能正确消费
### 2.4 海外任务下发到国内已跑通
已实现并验证:
- 海外导出待检测任务批次
- 国内 controller 主动拉取任务批次
- 国内本地写入 `domains`
- 国内本地生成 `detect_jobs` / `detect_job_items`
- 国内 worker 已开始执行实际检测任务
实际验证过的现象:
- 国内 `domains``0` 变成 `200`
- `detect/start` 能创建任务
- `job_id=1` 已进入 `running`
- `items_completed``items_running``items_claimed` 已持续变化
### 2.5 结果与运行时同步部分已跑通
已确认:
- 国内 `runtime_projection` 已成功推送到海外
- 国内 `detect_result_projection` 已开始生成
- 海外已能看到新的大陆 controller 节点在线
---
## 3. 本次实际修改过的核心代码
以下文件已经被修改,是后续接手时最需要优先查看的:
### 3.1 任务下发/同步相关
- [domain-api/app/services/sync_push_service.py](/www/wwwroot/getDomain/domain-api/app/services/sync_push_service.py:1)
- [domain-api/app/services/sync_record_service.py](/www/wwwroot/getDomain/domain-api/app/services/sync_record_service.py:1)
- [domain-api/app/api/routes/runtime.py](/www/wwwroot/getDomain/domain-api/app/api/routes/runtime.py:1)
- [domain-api/app/sync_agent.py](/www/wwwroot/getDomain/domain-api/app/sync_agent.py:1)
新增/补充的能力包括:
- `runtime_projection` 推送与接收
- `detect_result_projection` 推送与接收
- `detect_task_projection` 任务批次导出
- 国内 `pull_detect_task_batch_now()`
- 海外 `task-export`
- 海外 `task-ack`
- 国内任务批次入库逻辑
### 3.2 任务创建与控制
- [domain-api/app/services/detect_job_service.py](/www/wwwroot/getDomain/domain-api/app/services/detect_job_service.py:1)
- [domain-api/app/services/worker_control_service.py](/www/wwwroot/getDomain/domain-api/app/services/worker_control_service.py:1)
- [domain-api/app/services/runtime_control_service.py](/www/wwwroot/getDomain/domain-api/app/services/runtime_control_service.py:1)
- [domain-api/app/api/routes/detect.py](/www/wwwroot/getDomain/domain-api/app/api/routes/detect.py:1)
关键变化:
- 本地没有任务时,`create_detect_job_if_needed()` 会先尝试从海外拉一批任务
- Linux `systemd` 模式下不再强依赖 `sudo -n`
- 增加了 `pull_tasks` 运行时动作
### 3.3 运行时节点与 cluster 视图
- [domain-api/app/services/cluster_runtime_service.py](/www/wwwroot/getDomain/domain-api/app/services/cluster_runtime_service.py:1)
关键变化:
- 支持导入远端 runtime 节点
- 支持清理历史 `*-imported` 脏节点
- 正在补齐“海外显示大陆 worker 节点”的投影逻辑
### 3.4 前面已经做过的部署类改动
这些文件之前也已经做过较多修复,交接时可一起复核:
- `domain-api/deploy/multi-region/install_overseas_quick.sh`
- `domain-api/deploy/multi-region/install_mainland_controller_quick.sh`
- `domain-api/deploy/multi-region/install_mainland_worker_quick.sh`
- `docs/17_domainCheck_全流程部署实操手册.md`
- `docs/18_domainCheck_CentOS9一键复制部署与更新文档.md`
---
## 4. 当前仍未完全收尾的问题
### 4.1 海外 cluster 里大陆 worker 显示不完整
当前已经能在海外看到:
- `mainland-controller-01`
但一度没有稳定看到:
- `mainland-worker-01`
原因:
- 海外主要是根据大陆 controller 回传的 `runtime_projection` 做远端节点物化
- 之前 projection 里缺少 `active_job.node_stats`
- 后续已补代码,让海外可根据 `node_stats` 额外注册 worker 节点
接手人需要重点验证:
- 海外 `/api/v1/runtime/cluster` 中是否出现 `mainland-worker-01`
- `online_worker_nodes` 是否从 `0` 变为 `1`
### 4.2 历史脏节点 `mainland-control-imported`
这是早期调试阶段遗留的 imported 节点。
现象:
- 海外 `readiness` / `cluster` 曾显示:
- `mainland-control-imported`
- `status: offline`
影响:
- 不影响主流程执行
- 但会污染 readiness / cluster 展示
已经补了清理逻辑,但需要继续验证是否彻底清干净。
### 4.3 结果回传展示还需要继续观察
当前已经看到:
- `detect_result_projection` 在国内生成
- 海外 `sync-summary` 中出现结果相关记录
还需要继续确认:
- 海外是否稳定生成 `detect_result_ingest`
- 海外业务展示页/结果页是否正确反映国内执行结果
- 海外主库中的业务表是否已被正确更新
---
## 5. 两边部署时容易踩的坑
### 5.1 root 和 www 的职责不要混
建议约定:
- `git pull` / 仓库代码操作:用 `www`
- `systemctl restart ...`:用 `root`
原因:
- `root` 在当前环境下经常遇到 git safe.directory / ssh / dubious ownership 问题
- `www` 是仓库实际维护用户
### 5.2 国内 controller 与 worker 的 Redis 密码必须一致
至少这些位置要确认:
- `/etc/default/domaincheck-api`
- `/etc/default/domaincheck-worker`
- `/www/wwwroot/getDomain/domainCheck/.env`
如果 Redis 开了密码,但上述文件里 `REDIS_PASSWORD=` 为空,会出现:
- `Authentication required.`
- API 无法发 Worker 控制指令
- Worker 无法订阅控制消息
### 5.3 国内 controller 本地数据库并不是海外主数据
之前最大的误区就是:
- 海外有 `16w` 数据
- 但国内本地 `domains` 一开始是 `0`
当前设计已经调整为:
- 海外通过 `task-export` 导出待检测批次
- 国内主动拉批次,落本地最小 `domains`
- 国内 worker 只跑本地任务
不要再假设“国内本地库天然就有海外那 16w 主数据”。
### 5.4 代码更新要确认文件内容,不要只看 restart
如果 `systemctl restart domaincheck-api` 之后行为没变,不要只怀疑服务。
先直接检查源码关键片段是否真的更新到位。
例如本次调试里最典型的就是:
- `domain-api/app/services/sync_push_service.py`
通过 `grep` 关键代码判断是否已是新版,比只看服务状态更可靠。
---
## 6. 建议给海外 Codex 的接手任务
建议在海外机新开 Codex 后,直接按下面顺序接手:
### 6.1 第一优先级
- 确认海外 cluster 能稳定显示:
- `overseas-control-01`
- `mainland-controller-01`
- `mainland-worker-01`
- 确认海外 `readiness` 中:
- `online_worker_nodes >= 1`
- 不再被 `mainland-control-imported` 影响
### 6.2 第二优先级
- 确认 `detect_result_projection -> detect_result_ingest` 的闭环
- 确认海外业务查询接口/后台页面能看到国内执行回流结果
### 6.3 第三优先级
- 整理 `docs/18_domainCheck_CentOS9一键复制部署与更新文档.md`
- 把国内 controller / worker 的最终正确部署流程写成“复制即可执行”的版本
---
## 7. 建议的优秀调试方式:国内日志主动回调到海外
当前最大问题不是代码本身,而是:
- 每次都要在国内机执行命令
- 再手工复制长日志给海外
- 调试效率太低
最推荐的改法不是继续人工贴日志,而是做“日志回调到海外调试面板”。
### 7.1 推荐目标
增加一个轻量调试链路:
- 国内 controller
- 国内 worker
- 国内 sync-agent
把最近 N 条关键日志、关键事件、关键指标,主动推送到海外一个调试接口,或写入海外一张调试表。
### 7.2 最小可行方案
推荐只同步“结构化调试事件”,不要直接全量推原始日志文件。
建议结构:
- `source_region`
- `node_code`
- `service`
- `event_type`
- `level`
- `message`
- `payload_json`
- `created_at`
来源可以先选这三类:
- `domaincheck-api`
- `domaincheck-worker`
- `domaincheck-sync-agent`
### 7.3 最值得先回调的事件
不是所有日志都要回传,优先回传高价值事件:
- Worker 控制指令成功/失败
- 任务批次拉取成功/失败
- 任务创建成功/失败
- 结果投影生成成功/失败
- 结果同步推送成功/失败
- Redis/PostgreSQL 连接失败
- 代理池刷新结果摘要
- `domain_started` / `domain_completed` / `domain_failed`
### 7.4 为什么推荐结构化事件而不是原始日志
因为结构化事件更适合:
- 海外 Codex 直接查询分析
- 后台页面直接展示
- 做筛选、聚合、时间线回放
- 后续做自动告警
### 7.5 建议实现方式
建议海外增加一个轻量接口,例如:
- `POST /api/v1/runtime/debug-ingest`
国内三类服务把关键事件 POST 到海外。
海外落库到新表,例如:
- `detect_debug_events`
建议字段:
- `id`
- `source_region`
- `node_code`
- `service`
- `event_type`
- `level`
- `message`
- `payload_json`
- `created_at`
这样后面海外 Codex 只要直接查海外库,就能复原国内问题,不需要再人工复制日志。
---
## 8. 建议下一步实施顺序
### 方案 A先收尾展示再补日志回调
1. 修海外 cluster/readiness 的 worker 显示
2. 清理 `mainland-control-imported`
3. 确认结果回流展示
4. 再做日志回调
### 方案 B先补日志回调再继续深度调试
1. 海外新增 `debug-ingest`
2. 国内 controller / worker / sync-agent 回调关键事件
3. 海外 Codex 直接观察结构化事件
4. 再做 cluster/readiness 视图收尾
如果后续还要继续高频调试,我更推荐 **方案 B**
---
## 9. 当前阶段结论
截至本交接文档生成时,可以确认:
- 国内外任务下发链路已打通
- 国内本地任务落库已打通
- 国内 worker 已实际执行检测
- 国内运行时已回传海外
- 海外已能看到新的大陆 controller 节点
当前剩余问题已经从“主流程不通”降级为:
- 海外 cluster/readiness 视图收尾
- 结果回流展示补强
- 调试手段升级为结构化日志回调
主流程已经不再是 blocker。

View File

@@ -0,0 +1,262 @@
# domainCheck 临时海外控制面联调清单
适用场景:
- 暂时不使用正式海外机器
- 先把大陆 `controller + worker` 对接到当前测试海外机
- 先跑通“控制面 + 同步 + 观测”全链路,再切回正式海外环境
当前临时海外控制面:
- 节点编码:`overseas-control-01`
- 节点角色:`overseas / control`
- 机器 IP`152.53.37.118`
- 后台地址:`http://152.53.37.118/`
- API 基址:`http://152.53.37.118:8100`
## 1. 当前目标拓扑
本次联调按下面的角色分工:
- 大陆 controller
- 承担 API 控制面
- 承担 Sync Agent
- 可以兼跑本机 Worker
- 大陆 worker
- 只承担检测执行
- 临时海外控制面
- 只承担 API 控制与同步接收
- 不承载本机 Worker
- 不承载 Sync Agent
## 2. 临时海外控制面应有状态
在临时海外控制面机器上执行:
```bash
bash domain-api/deploy/multi-region/check_temp_overseas_control.sh
```
预期:
- `domaincheck-api``active (running)`
- `domaincheck-worker``inactive (dead)` 或禁用
- `runtime.status.data.node`
- `code=overseas-control-01`
- `region=overseas`
- `role=control`
- `runtime.status.data.worker.expected_on_this_node=false`
- `runtime.status.data.sync_agent.expected_on_this_node=false`
- `runtime.status.data.detect.phase_label=当前节点不承载`
## 3. 大陆 controller 切到临时海外控制面
在大陆 controller 上执行:
```bash
sed -i 's#^SYNC_TARGET_API_BASE_URL=.*#SYNC_TARGET_API_BASE_URL=http://152.53.37.118:8100#' /etc/default/domaincheck-api
sed -i 's/^SYNC_PUSH_ENABLED=.*/SYNC_PUSH_ENABLED=true/' /etc/default/domaincheck-api
systemctl restart domaincheck-api
systemctl restart domaincheck-sync-agent
systemctl restart domaincheck-worker
sleep 3
```
然后检查:
```bash
curl -s http://127.0.0.1:8100/api/v1/runtime/readiness
echo
curl -s http://127.0.0.1:8100/api/v1/runtime/sync-summary
```
预期:
- `runtime/readiness` 至少不是大陆本机配置错误导致的 `blocking`
- `runtime/sync-summary.data.enabled=true`
- `runtime/sync-summary.data.target_api_base_url=http://152.53.37.118:8100`
## 4. 大陆 worker 检查项
在大陆 worker 上执行:
```bash
bash domain-api/deploy/multi-region/check_mainland_worker.sh
```
预期:
- `NODE_CODE=mainland-worker-01`
- `NODE_REGION=mainland`
- `NODE_ROLE=worker`
- `domaincheck-worker``active (running)`
如果大陆 controller 也兼跑检测,再执行:
```bash
systemctl status domaincheck-worker --no-pager -l
echo
curl -s http://127.0.0.1:8100/api/v1/runtime/status
```
预期:
- `worker.running=true`
- `worker.expected_on_this_node=true`
## 5. 最短联调命令
### 5.1 在大陆 controller 上
```bash
bash domain-api/deploy/multi-region/check_temp_link.sh http://127.0.0.1:8100 http://152.53.37.118:8100
```
关注点:
- `push_sync` 返回 `code=0` 或幂等成功
- 不再出现目标地址为空
- 不再出现 `SYNC_PUSH_ENABLED=false`
关注点:
- `cluster` 中至少能看到:
- `overseas-control-01`
- 大陆 `mainland-controller-01`
- 大陆 `mainland-worker-01`
- `sync-summary` 中能看到来自大陆的接收记录
- `readiness` 不再是“完全单节点海外态”
## 6. 后台页面应如何理解
打开:
- `http://152.53.37.118/`
在运行中心里看到下面这些内容时,属于正常:
- `本机 Worker当前节点不承载`
- `Sync Agent当前节点不承载`
- `当前检测阶段:当前节点不承载`
- `代理运行态:不适用`
这不是故障,而是因为当前节点就是临时海外控制面。
真正应该关注的是:
- `集群节点`
- `有效执行节点`
- `同步状态`
- `多机就绪度`
## 7. 判断“到底有几台 Worker 在工作”
如果页面上“在线 Worker 数”和“实际正在跑检测的节点数”看起来不一致,以数据库为准。
在大陆 controller 上执行:
```bash
bash domain-api/deploy/multi-region/check_worker_participation.sh
```
判断规则:
- `detect_worker_nodes`
- 看谁在线
- 看谁是 `worker_online=true`
- `detect_participating=true` 只能说明它曾被判断为“正在参与”
- `detect_job_items`
- 看任务到底被哪台节点 `claimed_by`
- 这才是“当前真正干活的节点”
- `runtime/status`
-`participation_summary.dispatch_active_nodes`
- 这是“当前真正执行/领任务的节点”
-`participation_summary.non_participating_nodes`
- 这是“在线但未参与的节点”
-`non_participating_nodes[].participation_state`
- `standby` 表示在线待命
- `load_syncing` 表示负载待确认,不要直接算成“正在干活”
-`log_sync`
- 能直接确认远端日志回传是否开启、是关键还是全量、样本来自哪些节点
## 8. 常见误判
### 8.1 海外控制面显示“本机 Worker 不承载”
这是正常,不是故障。
### 8.2 页面显示“在线 Worker 1”但你部署了 2 台大陆机器
先区分:
- “有效执行节点”是可承担任务的在线节点数
- “当前参与检测节点”是当前真的在领任务、跑任务的节点
- “在线但未参与节点”是已经在线、可承接任务,但当前这轮还没分到任务的节点
如果 controller 没兼跑检测,通常只会看到独立 worker 在真正执行。
### 8.3 controller 机器也开了 worker 服务,但没有领任务
这不一定是 bug可能只是当前调度没有分到它。应以 `detect_job_items.claimed_by` 为准,不要只看服务在线。
### 8.4 页面显示“负载待确认”
这不是新的故障状态,而是为了避免误判:
- 节点已经上报 `busy` 或有 `current_load`
- 但当前还没看到明确的 `items_claimed / items_running / processed_recent`
通常是心跳和任务快照还没完全对齐。先等下一轮刷新,再结合 `claimed_by``participation_summary` 判断,不要立刻当作“这台机器已经在跑检测”。
### 8.5 日志控制台看不到大陆节点过程
先看 `runtime/status` 或页面里的“远端日志回传”:
-`enabled=false`
- 说明本来就没开回传
-`enabled=true``line_count=0`
- 说明开关已开,但当前还没有远端样本
-`source_nodes` 里没有目标大陆节点
- 说明该节点这轮还没回传日志,先看它是否真的在参与检测
## 9. 联调完成后的回滚
如果你后续要切回正式海外机器,在大陆 controller 上把目标地址改回正式值即可:
```bash
sed -i 's#^SYNC_TARGET_API_BASE_URL=.*#SYNC_TARGET_API_BASE_URL=http://正式海外控制面IP:8100#' /etc/default/domaincheck-api
systemctl restart domaincheck-api
systemctl restart domaincheck-sync-agent
sleep 3
```
如果临时海外控制面不再使用,可在该机器上保留 `domaincheck-api` 供后续调试,也可以停掉:
```bash
systemctl stop domaincheck-api
```
## 10. 本次临时海外控制面结论
当前这台测试海外机已经整理为:
-`overseas-control`
- API 正常
- Worker 不承载
- Sync Agent 不承载
- 数据已清空并按首装态初始化
- 可直接作为大陆 controller 的临时同步接收端
## 11. 配套脚本
- 临时海外控制面自检:
- `domain-api/deploy/multi-region/check_temp_overseas_control.sh`
- 大陆 controller -> 临时海外控制面联调检查:
- `domain-api/deploy/multi-region/check_temp_link.sh`
- 三机拓扑总览检查:
- `domain-api/deploy/multi-region/check_temp_topology.sh`
- 当前活跃任务由谁真正执行:
- `domain-api/deploy/multi-region/check_worker_participation.sh`
- 大陆 worker 本机自检:
- `domain-api/deploy/multi-region/check_mainland_worker.sh`

View File

@@ -0,0 +1,708 @@
# 21 domainCheck 海外主机集中运维与自动化方案
如果当前你不是在做“为什么要这么设计”的方案评审,而是已经进入真实收口、准备上线阶段,建议先跳转:
- `docs/25_domainCheck_海外单脑控制面上线收口总表.md`
- `docs/23_domainCheck_终局运维架构设计_海外单脑控制面.md`
- `docs/24_domainCheck_NodeAgent协议与ReleaseHub设计.md`
## 一、为什么要升级成“集中运维”
这段时间的多机联调已经证明一个事实:
- 现在这套“人在海外主机上看后台,再去大陆机器上手工跑命令、复制日志、判断状态”的方式,能联调,但效率很低
- 一旦节点数从 `2` 台增加到 `3` 台、`5` 台、`10` 台,复杂度会快速失控
- 国内机器上又不能稳定部署 Codex因此不能指望每台机器都具备“本机智能调试能力”
- 检测日志很大,靠人工复制日志片段,不适合做持续诊断
所以后续不应该继续堆更多“检查脚本”,而应该把整个体系升级成:
> 海外主机作为唯一运维控制面,统一接管大陆机器的安装、更新、重启、巡检、日志回流和故障诊断。
一句话目标:
> 只在海外主机操作,大陆机器尽量不需要人工登录。
---
## 二、最终目标形态
### 1. 海外主机承担什么
海外主机作为唯一控制面,承担:
- Web 后台
- API 控制面
- 运维任务中心
- 发布包仓库
- 节点注册与权限中心
- 日志汇聚与诊断入口
- 远程命令编排
- 巡检结果展示
也就是说,后续所有动作都从海外主机发起:
- 新机器纳管
- 初始化安装
- 发布更新
- 配置下发
- 服务重启
- 健康检查
- 采集诊断包
- 远端日志查看
- 故障一键排查
### 2. 大陆机器承担什么
大陆机器不再承担复杂控制逻辑,只承担:
- `domaincheck worker/controller` 本体服务
- 一个轻量 Node Agent
- 本机 systemd / 日志 / 版本 / 健康信息暴露
- 接收控制面任务并执行
- 将执行结果、日志、诊断包回传到海外主机
这意味着大陆机器以后是“被管理对象”,而不是“人工登录操作对象”。
---
## 三、推荐方案
## 方案 A海外控制面 + 大陆 Node Agent
这是我建议的主方案,也是长期最优方案。
### 核心思想
不要把“SSH 到每台机器执行命令”作为主链路,而是让每台大陆机器常驻一个 Agent
- Agent 主动连海外控制面
- Agent 拉取待执行任务
- 本地执行 systemd / shell / 发布 / 巡检
- Agent 把 stdout / stderr / 状态 / 日志游标回传
这样做的好处是:
- 不要求海外机能直接入站打通到大陆机
- 不要求每次人工 SSH
- 不怕 SSH 权限、跳板机、端口变化导致整套流程断掉
- 天然适合 NAT、弱网络、多机扩容
### 交互方式
建议 Agent 使用下面其中一种方式主动连海外控制面:
#### 首选HTTPS 长轮询
- `agent -> overseas-api`
- 周期拉取任务
- 周期上报心跳、版本、服务状态、日志摘要
优点:
- 实现最简单
- 最容易兼容现有 Python / FastAPI 架构
- 容易先落 MVP
#### 可升级WebSocket 常连
- 建立长连接
- 海外控制面可实时下发任务
- Agent 实时回传执行日志
优点:
- 更实时
- 日志流式体验更好
缺点:
- 第一版复杂度更高
### 为什么 Agent 比 SSH 更优
SSH 适合作为:
- 首次 bootstrap
- 临时人工兜底
- 非常规应急
但不适合作为日常主运维链路,因为:
- 节点一多,权限和连通性管理会变得脆弱
- 脚本回显、超时、日志采集很难标准化
- 人工 SSH 本质上还是“远程手工运维”
所以最佳做法是:
- SSH 只用于首次纳管
- 日常统一走 Agent
## 三点五、当前已经落地的第一版操作闭环
这套方案现在已经不只是设计稿,仓库里已经有一批可以直接使用的统一入口:
- `domain-api/deploy/multi-region/init_ops_center_config.sh`
- `domain-api/deploy/multi-region/drive_ops_center.sh`
- `domain-api/deploy/multi-region/drive_release_hub.sh`
- `domain-api/deploy/multi-region/drive_ops_action.sh`
- `domain-api/deploy/multi-region/build_node_agent_bootstrap_plan.sh`
推荐从海外控制面按这个顺序使用:
### 1. 初始化控制面配置
```bash
cd /opt/domaincheck/domain-api
bash domain-api/deploy/multi-region/init_ops_center_config.sh \
/etc/default/domaincheck-ops-center \
http://121.204.244.188:8100 \
http://152.53.37.118:8100 \
https://api.example.com
```
### 2. 查看当前统一配置
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh config
```
### 3. 在控制面本机生成发布包
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh release-package
bash domain-api/deploy/multi-region/drive_ops_center.sh release-launchpad
bash domain-api/deploy/multi-region/drive_ops_center.sh release-preview
bash domain-api/deploy/multi-region/drive_ops_center.sh release-preview-smart worker
bash domain-api/deploy/multi-region/drive_ops_center.sh release-show
```
### 4. 导出一份联调/交接报告
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-export
```
### 5. 为新节点导出接管计划
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh agent-plan-export \
/opt/domaincheck/domain-api/runtime/ops-center-reports/agent-plans \
http://127.0.0.1:8100 \
mainland-worker-02 \
mainland \
worker \
https://api.example.com \
/opt/domaincheck
```
这五步对应的意义分别是:
- 先统一控制面默认地址和身份
- 再确认驾驶舱当前在看哪个环境
- 再把发布物、发布前预检和发版驾驶舱都收回统一入口,不再额外记根目录脚本
- 再把现场收敛成可以回看、可以交接的报告
- 最后为新增节点生成标准接管方案
这样后面无论是海外 Codex 自动驾驶、后台按钮,还是人工运维,都不再需要先去大陆机器手工拼命令。
## 三点六、现在发布驾驶舱已经进入统一数据口径
目前发布侧也已经不是零散接口拼出来的状态,而是收敛成了一套统一判断:
- `GET /api/v1/ops/releases/launchpad`
- `ops overview -> release_hub.launchpad`
- `check_release_hub.sh`
- `drive_release_hub.sh launchpad`
- 运维中枢页面里的“发布驾驶舱”
这几处现在复用的是同一套结论,都会统一告诉你:
- 当前是 `ready / attention / blocked`
- 最新发布包是否可用
- 最新 Release 是否已经建立
- Worker 智能灰度是否可发
- Control 发布是否可发
- 下一步推荐动作是什么
同时,`GET /api/v1/ops/runbook` 里的标准作业路径 `release_progression` 也已经切到同一套发布驾驶舱判断。
也就是说,海外控制面看到的“标准作业路径”和“发布驾驶舱”不会再出现一套说能发、一套说先补接管的分裂口径。
现在又往前推进了一步:
- `POST /api/v1/ops/runbook/sequences/{sequence_key}/execute`
后台上的标准作业路径按钮,后续都应该优先走这个入口,再由后端统一分发到 driver action / playbook / rollout 预案,而不是前端自己维护动作分支。
这样后续海外 Codex、后台按钮和命令行脚本拿到的就不再是三套不同口径而是同一套“发布驾驶判断”。
## 三点七、现在回执队列也已经进入统一治理入口
除了发布驾驶舱Node Agent 回执队列这一层现在也已经不再是“只能看、不能管”的状态。
当前已经统一收口成三类入口:
- 页面:
- OpsCenter 托管节点表可以直接打开“回执队列治理”抽屉
- 驾驶建议:
- `dead_letter / retrying` 会优先落到标准动作模板
- 海外单入口 CLI
- `drive_ops_center.sh queue-status`
- `drive_ops_center.sh queue-records`
- `drive_ops_center.sh queue-flush`
- `drive_ops_center.sh queue-replay`
- `drive_ops_center.sh queue-replay-record`
- `drive_ops_center.sh queue-discard-record`
这意味着海外主机已经可以统一处理:
- 哪台节点存在积压 / 死信
- 头部记录是什么
- 什么时候应该立即冲刷
- 什么时候应该重放
- 什么时候应该说明原因后丢弃
当前阶段仍然明确限制为:
- `record_visibility=head_only`
- 所有治理动作都落成正式 `ops job`
- 不直接 SSH 到节点改队列文件
这样以后即使把远端全量死信记录正式投影到控制面,也只是“扩可见范围”,而不是重新推翻当前模型。
---
## 四、这套方案要解决的具体问题
## 1. 安装部署自动化
目标:
- 海外控制面点一次“新增节点”
- 填一个节点模板
- 大陆机器自动初始化
建议流程:
1. 海外后台新增节点
2. 生成 `bootstrap token`
3. 大陆机器只执行一次极短安装命令
4. Node Agent 注册到海外控制面
5. 控制面向该节点下发:
- 拉取发布包
- 解压
- 生成 `/etc/default/...`
- 安装 systemd
- 启动服务
6. 回传安装结果
这样后续加机器时,不需要再重复人工对照文档逐条敲。
## 2. 更新发布自动化
目标:
- 海外主机统一推版本
- 大陆节点自动拉包、灰度更新、失败回滚
这里强烈建议:
> 后续不要让大陆机器自己跑 git 作为正式更新链路。
而是改成:
- 海外控制面构建发布包
- 版本号固定
- Agent 下载指定 release 包
- 校验 checksum
- 切换当前版本软链
- 重启服务
- 回传成功/失败
这样比远程 `git pull` 更稳,因为:
- 不依赖每台机器 git 权限
- 不怕工作区脏文件
- 不怕 root/www 用户混用
- 可回滚
推荐目录形态:
```text
/opt/domaincheck/releases/<version>/
/opt/domaincheck/current -> /opt/domaincheck/releases/<version>/
```
更新时:
- 下载新版本到 `releases`
- 校验
- 切换 `current`
- `systemctl restart ...`
失败就回滚软链。
## 3. 远程命令执行自动化
目标:
- 海外控制面能发“结构化任务”
- 不再让人手工复制命令
建议任务类型:
- `service.start`
- `service.stop`
- `service.restart`
- `service.status`
- `deploy.release`
- `config.render`
- `diagnostics.collect`
- `logs.tail`
- `script.run`
- `health.check`
每个任务统一回传:
- 任务 ID
- 节点编码
- 开始时间 / 结束时间
- exit code
- stdout
- stderr
- 结构化结果 JSON
这样后面后台才能真正做“操作中心”。
## 4. 日志集中回流
目标:
- 海外后台就能看到大陆机器日志
- 不再人工抄 `journalctl`
### 日志回流建议分三层
#### A. 关键事件流
只回传关键事件:
- 服务启动
- 服务重启
- 任务开始
- 任务完成
- 代理刷新失败
- Redis/DB 连接异常
- 第三方站点异常
适合默认长期开启。
#### B. 诊断模式日志流
像你现在提的“关闭 / 关键 / 全量回传”一样:
- `off`
- `key`
- `full`
这是正确方向,应该继续保留。
#### C. 诊断包
当出现疑难问题时,一键打包:
- 最近 N 分钟 `journalctl`
- `runtime/status`
- `runtime/cluster`
- `detect_worker.log tail`
- `/etc/default/*`
- 当前版本号
- 本机健康检查输出
然后上传海外主机。
这比全量实时传所有日志更经济,也更适合定位问题。
## 5. 健康巡检自动化
目标:
- 每台大陆机自动自检
- 海外后台只看结果
建议 Agent 每 30 秒到 60 秒上报:
- 节点在线状态
- 当前版本
- API / Worker / Sync Agent 运行态
- Redis / PostgreSQL / 磁盘 / 内存 / CPU
- 最近告警
- 当前任务负载
- 最近日志时间
并把现有脚本升级为 Agent 内部检查项:
- `check_mainland_controller.sh`
- `check_mainland_worker.sh`
- `check_temp_topology.sh`
- `check_worker_participation.sh`
后续不是人工执行这些脚本,而是 Agent 周期性执行并结构化上传结果。
---
## 五、建议的系统分层
## 1. 海外控制面
建议新增一个“运维控制模块”,逻辑上可放进 `domain-api`,后续再拆独立服务也可以。
### 需要的核心对象
#### `managed_nodes`
记录纳管节点:
- `node_code`
- `region`
- `role`
- `hostname`
- `ip`
- `agent_version`
- `current_release`
- `status`
- `ssh_enabled`
- `agent_last_seen_at`
- `tags`
#### `ops_jobs`
记录运维任务:
建议以后直接以 [ops_job_contract.md](/www/wwwroot/getDomain/docs/schemas/ops_job_contract.md:1) 为正式母本。
- `job_id`
- `job_type`
- `target_nodes`
- `payload`
- `created_by`
- `status`
- `started_at`
- `finished_at`
#### `ops_job_steps`
记录每个节点执行步骤:
- `node_code`
- `step_name`
- `status`
- `stdout`
- `stderr`
- `result_json`
#### `node_log_streams`
记录日志游标和日志回流状态:
- `node_code`
- `source`
- `mode`
- `cursor`
- `last_received_at`
## 2. Node Agent
建议单独做一个轻量 Python 服务,比如:
```text
domaincheck-node-agent
```
职责:
- 周期心跳
- 拉取任务
- 本地执行
- 采集日志
- 上报结果
- 生成诊断包
Agent 尽量独立于业务主程序,不要把它耦合进 `detect_worker.py`
原因:
- 运维系统不能依赖业务进程是否正常
- 即使 Worker 崩了Agent 还应该活着,才能帮你排障
---
## 六、对你当前项目最合适的落地路线
## 第一阶段:先做“控制面集中化”
目标:
- 海外后台统一看到所有大陆机器
- 一键拉诊断
- 一键执行已有检查脚本
- 一键切日志回传模式
这个阶段先不碰太多发布链路,优先把“看”和“查”统一。
### 交付物
- Node Agent MVP
- 海外后台“节点管理”页
- 海外后台“运维任务”页
- 海外后台“远端日志”页
- 海外后台“诊断包”页
## 第二阶段:再做“一键更新”
目标:
- 海外控制面选择版本
- 指定节点灰度发布
- 自动回滚
### 交付物
- 发布包生成器
- `release manifest`
- Agent 下载 / 校验 / 切换版本
- 回滚机制
## 第三阶段:再做“一键安装新节点”
目标:
- 新机器只执行一次 bootstrap
- 其余全部由海外控制面接管
### 交付物
- bootstrap token
- 安装向导
- 节点注册流程
- 环境模板生成器
---
## 七、比“SSH 全接管”更优的地方
你提的方向是:
> 海外主机配置好 SSH后续所有大陆机器都由代码内部接管
这个方向本身是对的但如果只做“SSH 全接管”,还不够优秀。
更优解是:
> SSH 只作为纳管和兜底方式;日常统一走 Agent 主动连接。
这样好处是:
- 架构更稳
- 不依赖每次远程入站打通
- 不怕某些网络环境 SSH 不稳定
- 更适合未来节点继续增加
- 更容易做权限分级、审计、结果留痕
所以我建议最终定成:
### 运维主链路
- `海外控制面 -> Agent 任务编排 -> 大陆节点执行 -> 回传结果`
### 运维兜底链路
- `海外控制面 -> SSH -> 大陆节点`
---
## 八、和现有代码如何衔接
当前项目已经有一些很好的基础,不需要推翻:
- 多机节点模型
- `runtime/status`
- `runtime/cluster`
- `sync-summary`
- 一批巡检脚本
- 日志回传开关雏形
- 运行中心
这些都应该保留,并演进成:
### 当前脚本的未来定位
- `bootstrap_*.sh`
- 保留为 bootstrap / 应急工具
- `check_*.sh`
- 演进成 Agent 内部的标准诊断动作
- `runtime/status`
- 继续作为统一运行态接口
- `runtime/cluster`
- 继续作为统一集群视图
- `detect_result_projection / runtime_projection`
- 继续作为跨地域观测基础
也就是说,现有代码不是废掉,而是从“人工脚本时代”升级成“控制面编排时代”。
---
## 九、我建议的最优落地决策
如果只选一个方向,我建议直接定成:
### 最优方案
- 海外主机为唯一控制面
- 大陆节点统一部署 `domaincheck-node-agent`
- Agent 主动访问海外控制面
- 日常安装、更新、巡检、日志回流全部走 Agent
- SSH 仅保留为 bootstrap 和应急手段
- 正式更新统一改为 release 包分发,不再把 `git pull` 作为正式更新链路
这是当前最值得投入的方向,因为它能同时解决:
- 调试效率低
- 多机管理复杂
- 权限混乱
- 日志分散
- 更新不稳定
- 新增节点成本高
---
## 十、建议的下一步执行顺序
不要再继续先补散点 bug而是先把运维骨架建起来。
建议顺序:
1. 固化这份方案
2. 新建 `node-agent` 设计草案
3. 先做 Agent MVP
4. 先接入:
- 心跳
- 远程任务
- 诊断包
- 日志 tail
5. 海外后台新增:
- 节点管理页
- 运维任务页
- 远端日志页
6. 再把现有检查脚本封成 Agent 动作
7. 最后再做发布链路自动化
---
## 十一、结论
当前最优策略不是“继续加脚本”,而是:
> 把 domainCheck 从“多机联调项目”升级成“海外控制面统一接管大陆节点的自动化运维系统”。
从长期看,这会比继续靠人工 SSH、人工复制日志、人工比对状态高效很多也更符合你后续继续扩机器的目标。

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,430 @@
# 25 domainCheck 海外单脑控制面上线收口总表
## 一、这份文档解决什么问题
这份文档不是再讲设计,而是把当前项目进入正式上线前,真正需要收口的事项压成一张总表。
适用场景:
- 海外主机已经作为单脑控制面
- 大陆节点已经开始纳管
- Ops Center / Codex Driver / CLI 都已经接入同一套 `ops` contract
- 目标从“能联调”切换到“能稳定上线、能持续运维”
这份文档优先回答 4 个问题:
1. 现在能不能继续收口
2. 现在能不能正式发布
3. 还有哪些阻断项没清
4. 下一步到底先跑哪条命令
---
## 二、上线前统一原则
上线前必须统一成下面这条工作方式:
- 海外主机作为唯一主驾驶席
- 页面、CLI、Codex 共用同一套后端判断
- 默认先看 `go-live-summary`
- 真要解释原因时再下钻 `stack-diagnosis`
- 真要执行动作时走 `driver-resolve / execute-resolved`
- 真要发布或放量时走 `Release Hub / rollout`
不再推荐:
- 人工分别登录多台大陆机器拼状态
- 每次上线都从 `journalctl + systemctl + curl` 临时组合判断
- 前端、CLI、Codex 各自维护不同的默认下一步
---
## 三、正式上线门禁
### 1. 收口门禁
至少同时满足:
- `go_live_summary.go_live_status != blocked`
- `stack_diagnosis.diagnosis.stack_status != blocked`
- `route_surface_complete=true`
- `driver-feed.automation_coverage.launch_status != blocked`
- 首屏默认下一步已经明确,不再是模糊人工判断
### 2. 发布门禁
至少同时满足:
- `publish_ready=true`
- `launchpad_status != blocked`
- 不存在未处理的关键 `blocking_reasons`
- 当前发布主车道已经清晰落在:
- `review_smart_rollout_preview`
- `review_control_rollout`
- `publish_latest_worker`
- `create_release_rollout_*`
### 3. 运维门禁
至少同时满足:
- 海外控制面 API 稳定在线
- 大陆 controller / worker 心跳稳定
- 节点接管缺口已经收口,或至少首个缺口节点已有明确恢复动作
- 远端日志回传可按需开启、复核、关闭
- 运行中心首屏能直接区分:
- 在线但未参与
- 正在执行 / 正在领任务
---
## 四、真正的起手顺序
每次准备上线、复核、值班接手时,都按这个顺序来:
### 第 1 步:看上线收口摘要
```bash
cd /www/wwwroot/getDomain
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-check http://127.0.0.1:8100 http://127.0.0.1:8100 summary
```
如果当前是临时海外控制面联调,也可以把第二个地址替换成海外目标 API。
第一眼重点只看:
- `go_live_status`
- `publish_status`
- `blocking_reasons`
- `warnings`
- `next_step_action_code`
- `operator_title`
如果你怀疑当前是环境本身有漂移,而不是业务链路没收口,先执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh env-audit
bash domain-api/deploy/multi-region/drive_ops_center.sh runtime-refresh-recover
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover
```
重点只看:
- `status`
- `headline`
- `missing_items`
- `tooling_items`
- `runtime.preflight_ok`
- `runtime.readiness_status`
- `runtime.route_surface_complete`
- `runtime.repo_capability_drift`
- `runtime.runtime_may_need_restart`
- `recommended_actions`
如果这里出现:
- `runtime.repo_capability_drift=true`
- `runtime.runtime_may_need_restart=true`
则优先执行 `runtime-refresh-recover`,不要先把问题误判成“代码还没写完”。这通常表示:
- 仓库代码已经更新
- 但运行中的 `domaincheck-api` 进程还没重启到这版代码
`runtime-refresh-recover` 会固定给出:
- 当前是否真的属于运行时版本漂移
- 推荐先跑的 `runtime-refresh-recover` 统一恢复入口
- 重启后应该按什么顺序继续:
- `stack-diagnosis`
- `node-bootstrap-plan`
- `stack-next`
- `doctor-decision`
如果你已经不想再手工一条条执行,而是想把“刷新运行时 + 再做总检复核”压成一次操作,直接执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover
```
它会固定串起:
1. `runtime-refresh-recover`
2. `stack-diagnosis summary`
3. `stack-next`
4. `go-live-check summary`
5. `doctor-decision`
如果要把这次上线前检查直接导出成一整包证据,而不是手工复制多段终端输出,直接执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-export
```
它会统一导出:
- `env-audit`
- `go-live-check` 摘要
- `go-live-summary`
- `stack-diagnosis`
- `driver-feed`
- `codex-brief`
- `release-launchpad`
- `doctor-decision`
- `doctor-export`
- `manifest.json`
其中 `manifest.json` 会直接标记:
- 环境审计当前是 `ready / attention / blocked`
- 哪些 artifact 成功
- 哪些 artifact 超时
- 哪些 endpoint 缺失或返回异常
- 当前推荐的阅读顺序
现在 Ops Center 首屏也会同步读取最新 bundle / manifest
- 顶部 `总检决策`
- 详情区 `总检主决策详情`
- API `GET /api/v1/ops/doctor-decision`
- 顶部 `交付证据`
- 详情区 `交付证据详情`
- API `GET /api/v1/ops/go-live-bundle`
- 顶部 `正式复核`
- 详情区 `正式复核详情`
- API `GET /api/v1/ops/go-live-review`
如果你想先拿到一句“bundle manifest 正式复核是否通过”的统一结论,而不是直接跳到最终签收,也可以先执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-review
```
如果你想在 bundle 基础上直接得到一句“现在能不能签字上线”的统一结论,而不是人工再看多份 JSON直接执行
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-signoff
```
或基于已有 bundle
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-signoff /path/to/go-live-bundle
```
这里的 `go-live-signoff` 已经不是另一套独立摘要,而是固定压缩:
- `go-live-review`
- `doctor-decision`
- `go-live-summary / 发布门禁 / launchpad 摘要`
所以页面首屏、CLI 与海外 Codex 看到的是同一份最终签字口径。
第一眼重点只看:
- `signoff_status`
- `headline`
- `release_gate`
- `blocked_reasons`
- `attention_reasons`
- `decision`
### 第 2 步:看总检详情
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh stack-diagnosis
```
重点只看:
- `stack_status`
- `issues`
- `next_step`
- `quick_commands`
### 第 3 步:看驾驶主线
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh driver-feed
bash domain-api/deploy/multi-region/drive_ops_center.sh codex-brief
```
重点只看:
- `top_recommendation`
- `automation_coverage`
- `recommended_behavior`
- `focus`
### 第 4 步:确认默认下一步
如果只是预览:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh stack-next
```
如果已经确认要执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh stack-next run confirm
```
---
## 五、当前项目的主处理车道
上线前遇到问题时,不要发散排查,先归到下面 5 条主车道:
### 1. 节点接管车道
典型信号:
- `remote_access_ready=0`
- `bootstrap_run`
- `run_acceptance`
- `managed_nodes_agent_pending`
优先命令:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh agent-gap-check
bash domain-api/deploy/multi-region/drive_ops_center.sh agent-gap-recover
bash domain-api/deploy/multi-region/drive_ops_center.sh node-onboarding http://127.0.0.1:8100 mainland-worker-01
```
### 2. 远端日志车道
典型信号:
- 首屏显示“现场日志覆盖不足”
- `log_sync_enabled=false`
- `line_count=0`
- `source_nodes` 缺节点
优先命令:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh log-sync-check
bash domain-api/deploy/multi-region/drive_ops_center.sh log-sync-recover
bash domain-api/deploy/multi-region/drive_ops_center.sh scene-node-log http://127.0.0.1:8100 mainland-worker-01 120 key
```
### 3. 总检修复车道
典型信号:
- `stack_status=blocked`
- `surface_status=broken`
- `contracts` / `launchpad` / `activity-stream` 缺口
优先命令:
```bash
bash domain-api/deploy/multi-region/check_ops_center_stack.sh http://127.0.0.1:8100
bash domain-api/deploy/multi-region/check_ops_contracts.sh http://127.0.0.1:8100
bash domain-api/deploy/multi-region/check_release_hub.sh http://127.0.0.1:8100
```
### 4. 检测参与车道
典型信号:
- 页面显示在线节点多,但真正跑检测的少
- `claimed_by` 分布异常
- 在线但未参与节点过多
优先命令:
```bash
bash domain-api/deploy/multi-region/check_worker_participation.sh
bash domain-api/deploy/multi-region/drive_ops_center.sh activity-stream
```
### 5. 发布 / 放量车道
典型信号:
- `publish_ready=true`
- `launchpad_status` 已可进入 Worker / Control rollout
- 默认下一步已落在 Release Hub
优先命令:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh release-launchpad
bash domain-api/deploy/multi-region/drive_ops_center.sh codex-focus-preview
```
---
## 六、首屏通过标准
Ops Center 首屏如果要算“可上线收工”,至少应满足:
- 首屏能同时显示:
- 上线收口状态
- 发布闸门状态
- 自动化收口状态
- 主处理车道
- 默认下一步
- 后端接管覆盖
- 观察层完整度
- 现场日志覆盖度
- 首屏动作条可直接完成:
- 默认下一步
- 定位下一步
- 看契约
- 复制命令
- 进入主处理面板
- 首屏回执条能统一反馈:
- 打开契约成功
- 定位成功
- 复制成功
- 后端动作执行成功 / 警告 / 失败
如果这些已经稳定,就说明值班同事和海外 Codex 已经在同一个驾驶台上工作,而不是各自再拼逻辑。
---
## 七、通过标准后的最小上线动作
当上面门禁都通过后,建议最小上线动作顺序为:
1.`go-live-check`
2.`stack-diagnosis`
3. 复核 `driver-feed.automation_coverage`
4. 复核 `codex-brief.recommended_behavior`
5. 若进入发布车道,先看 `release-launchpad`
6.`guarded_auto` 动作显式确认后再执行
上线前最后一轮建议保留证据:
- `go-live-summary` 输出
- `stack-diagnosis` 输出
- `driver-feed` 输出
- `codex-brief` 输出
- `release-launchpad` 输出
- 前端构建成功记录
---
## 八、现在这套体系是否已经进入可上线状态
按当前仓库现状,可以认为已经具备:
- 单脑控制面的协议骨架
- 首屏驾驶舱骨架
- 总检与驾驶 contract
- Release Hub / Driver / Node Agent 的联动骨架
- 海外 CLI 单入口
但正式宣称“可以上线”,仍建议每次以这份总表复核,而不是只凭某一个页面截图或某一次联调成功就直接跳过。
这份文档的定位就是:
> 后续每次上线、值班接手、发布前复核,都先回到这里。
如果你已经准备进入“这次要不要真的发”的最终执行阶段,下一份应直接看:
- `docs/26_domainCheck_发布前运行验证与交付模板.md`

View File

@@ -0,0 +1,635 @@
# 26 domainCheck 发布前运行验证与交付模板
## 一、这份模板怎么用
这份文档不是设计说明,而是正式发布前最后一轮执行模板。
适用场景:
- 海外单脑控制面已经搭好
- 大陆节点已经接入或正在收口
- 代码已经更新到待发布版本
- 现在要做最后一轮运行验证、证据留存、交付确认
这份模板分成 3 段:
1. 发布前运行验证
2. 上线证据导出
3. 最终交付结论模板
---
## 二、发布前运行验证
### 1. 先跑统一收口摘要
```bash
cd /www/wwwroot/getDomain
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-check http://127.0.0.1:8100 http://127.0.0.1:8100 summary
```
记录结果:
- `go_live_status`
- `publish_status`
- `blocking_reasons`
- `warnings`
- `next_step_action_code`
- `operator_title`
- `launchpad_recommended_target_node_code`
- `launchpad_recommended_recovery_label`
- `launchpad_recommended_recovery_summary`
- `launchpad_onboarding_bootstrap_pending_nodes`
- `launchpad_onboarding_acceptance_ready_nodes`
通过标准:
- `go_live_status != blocked`
- `publish_status != blocked`
### 1.5 先看环境差异是否已收口
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh env-audit
bash domain-api/deploy/multi-region/drive_ops_center.sh runtime-refresh-recover
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover
```
重点只看:
- `status`
- `headline`
- `python.pytest_installed / fastapi_installed / uvicorn_installed`
- `python.runtimes`
- `services`
- `runtime.preflight_ok`
- `runtime.readiness_status`
- `runtime.route_surface_complete`
- `missing_items`
- `tooling_items`
通过标准建议:
- `status != blocked`
- `runtime.preflight_ok=true`
- `route_surface_complete=true`
- 如果 `missing_items` 里仍有关键基础项,先补环境,再继续业务复核
- 如果只有 `tooling_items`,可以继续上线复核,但建议后补本机工具链
- 如果 `runtime.runtime_may_need_restart=true`
- 不要直接继续接管或发布链
- 先按 `runtime-refresh-recover` 给出的固定顺序完成 API 重启与复检
- 如果你希望把这一轮“重启 + 总检 + 默认下一步 + 上线摘要”压成一次复核
- 直接执行 `go-live-recover`
### 1.6 先看托管节点接入面是否清楚
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh nodes http://127.0.0.1:8100
```
重点只看:
- `summary.agent_ready`
- `summary.ssh_ready`
- `summary.remote_access_ready`
- `summary.remote_access_state_counts`
- 每台节点的 `agent_state`
- 每台节点的 `remote_access_state`
- 每台节点的 `ssh_access_label`
- 每台节点的 `ssh_entry`
通过标准建议:
- 如果某台节点还是 `agent_pending`
- 先确认是否已经保存 SSH 入口
- 如果节点尚未保存 SSH 入口,但你已经决定由海外控制面统一接管
- 先补录:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh node-bind-ssh http://127.0.0.1:8100 mainland-worker-01 121.204.244.248 root 22
```
- 补录后立即复查:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh nodes http://127.0.0.1:8100
bash domain-api/deploy/multi-region/drive_ops_center.sh node-handover http://127.0.0.1:8100 mainland-worker-01
```
- 如果已经 `agent_ready`
- 说明该节点已进入标准远端执行器接管面
- 如果还不是 `agent_ready`,但 `ssh_ready` 已经成立
- 说明至少已经具备海外主控经 SSH 进入节点完成 bootstrap / 验收的前置条件
### 2. 再看总检详情
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh stack-diagnosis
```
记录结果:
- `stack_status`
- `issues`
- `next_step`
- `quick_commands`
通过标准:
- `stack_status != blocked`
- `issues` 里没有未处理的关键阻断项
### 3. 再看驾驶主线
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh driver-feed
bash domain-api/deploy/multi-region/drive_ops_center.sh codex-brief
```
记录结果:
- `top_recommendation`
- `automation_coverage`
- `recommended_behavior`
- `focus`
- `summary.launchpad_recommended_target_node_code`
- `summary.launchpad_recommended_recovery_label`
- `summary.launchpad_onboarding_bootstrap_pending_nodes`
- `summary.launchpad_onboarding_acceptance_ready_nodes`
通过标准:
- `automation_coverage.launch_status != blocked`
- 默认下一步已经明确
- 如果 `summary.launchpad_recommended_target_node_code` 非空
- 值班同事应能直接知道当前卡在哪台节点
- 不需要再回 launchpad 明细手工翻 gap rows
### 4. 若涉及发布,再看 Release Hub
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh release-launchpad
```
记录结果:
- `launchpad_status`
- `recommended_action_code`
- `default_rollout_gate_status`
- `recommended_target_node_code`
- `recommended_recovery_label`
- `recommended_recovery_summary`
- `onboarding_bootstrap_pending_nodes`
- `onboarding_acceptance_ready_nodes`
通过标准:
- `launchpad_status != blocked`
- `default_rollout_gate_status != blocked`
特殊判读:
- 如果 `recommended_action_code=api-restart`
- 不要误判成“节点没接好”
- 这更像是运行中的控制面 API 还没刷新到当前仓库的最新运维能力
- 应先执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh runtime-refresh-recover
```
- 然后重新跑:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh stack-diagnosis
bash domain-api/deploy/multi-region/drive_ops_center.sh release-launchpad
```
补充说明:
-`latest_release.json` 直接创建 Release或执行“基于最新包的一键智能 Rollout”之前
- 现在不仅要求 `smoke_test_ok=true`
- 还要求当前 `final_release_report.json` 与最新包完全匹配,且 `final_release_ok=true`
- 如果页面按钮被禁用,或 API 返回“最新发布包尚未完成最终签收”
- 优先检查 `final_release_report_stale_reason`
- 再检查 `final_release_gate_decision / final_release_gate_blocked_reasons`
### 5. 若涉及节点接管,补跑节点验收
如果这次发布包含:
- 新增大陆节点
- 重新接管旧节点
- 切换到 Node Agent 主接管模式
则不能只看总检摘要,还要对目标节点逐台完成验收。
先看验收计划:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh node-acceptance-plan http://127.0.0.1:8100 mainland-worker-01
```
确认无误后执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh node-acceptance-run http://127.0.0.1:8100 mainland-worker-01 cli/acceptance
```
记录结果:
- `node_code`
- `status`
- `checks`
- `blocking_issues`
- `warnings`
- `recommended_next_step`
通过标准:
- `status != blocked`
- 没有未处理的 `blocking_issues`
- 目标节点已经不再停留在“bootstrap pending / acceptance pending”
### 6. 若涉及远端执行,补跑日志回传验证
如果当前版本准备进入:
- 多机值班
- 海外单脑统一接管
- 远端动作回执与现场日志复核
则需要确认日志回传链已经可用,而不是只看节点在线。
先检查:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh log-sync-check
```
如果存在缺口,再执行恢复:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh log-sync-recover http://127.0.0.1:8100 key confirm cli/log-sync
```
必要时抓一份节点现场日志:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh scene-node-log http://127.0.0.1:8100 mainland-worker-01 120 full
```
记录结果:
- `log_sync_enabled`
- `line_count`
- `source_nodes`
- `missing_nodes`
- `scene_log.status`
通过标准:
- 关键节点已出现在 `source_nodes`
- `missing_nodes` 不包含当前发布主车道节点
- 如需人工复核现场,`scene-node-log` 能取到有效日志
### 7. 若涉及 Node Agent 交付,补看队列健康
如果这轮发布已经进入“控制面发动作、节点拉任务、节点回执结果”的模式,就必须确认 delivery queue 没有假健康。
先看队列摘要:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh queue-status http://127.0.0.1:8100 mainland-worker-01
```
如果怀疑有堆积或死信,再看明细:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh queue-records http://127.0.0.1:8100 mainland-worker-01 dead_letter
```
如需重放:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh queue-replay http://127.0.0.1:8100 mainland-worker-01 20 cli/queue-replay
```
记录结果:
- `delivery_queue.summary`
- `dead_letter`
- `retrying`
- `pending`
- `replayed_count`
通过标准:
- `dead_letter=0`
- 没有持续增长的 `retrying`
- 队列不处于异常堆积状态
注意:
- `dead_letter > 0` 时,不应宣称“可正式发布”
- 这种情况至少按 `publish_status = blocked` 处理
### 8. 最后跑一次 doctor 结论
前面的检查是分面复核最后还要再收成一句话让交班、值班、Codex 驾驶员看到同一结论。
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-decision
```
记录结果:
- `status`
- `decision`
- `recommended_commands`
- `recommended_reading_order`
- `launchpad_alignment`
通过标准:
- `status != blocked`
- `decision` 与前面的 `go-live-check / stack-diagnosis / release-launchpad` 不冲突
- `recommended_commands` 已经指向明确的下一跳,而不是泛化排查
### 9. 若希望直接生成“可否签字上线”的最终摘要
如果你不想手工再拼:
- bundle review
- doctor 结论
- 发布门禁
可以直接执行:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-signoff
```
如果已经有现成证据包,也可以直接基于 manifest 输出:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-signoff /path/to/go-live-bundle
```
这一步现在不是“另一套单独判断”,而是固定复用:
- `go-live-review`
- `doctor-decision`
- `go-live-summary / 发布门禁 / launchpad 摘要`
也就是说页面首屏、CLI 和海外 Codex 看到的最终签收结论,已经开始共享同一份签字口径。
重点只看:
- `signoff_status`
- `headline`
- `release_gate`
- `blocked_reasons`
- `attention_reasons`
- `decision`
- `recommended_commands`
通过标准:
- `signoff_status=ready`
- 可进入最终人工签字或正式发布
- `signoff_status=attention`
- 说明现场已经接近完成,但仍应先清 attention 项
- `signoff_status=blocked`
- 本轮不应宣称收口完成
---
## 三、上线证据导出
### 1. 导出 bundle
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-export
```
这会生成一整包上线前证据。
建议至少保留:
- `00_env_audit.txt`
- `01_go_live_check_summary.txt`
- `02_go_live_summary.json`
- `03_stack_diagnosis.json`
- `04_driver_feed.json`
- `05_codex_brief.json`
- `06_release_launchpad.json`
- `manifest.json`
如果当前轮次涉及节点接管,建议额外保留:
- `agent_gap_export.json`
- `node_bootstrap_plan.txt`
- `node_acceptance_plan.json`
如果当前轮次涉及远端执行与日志回传,建议额外保留:
- `scene_log_*.txt`
- `doctor_decision.json`
### 2. 直接复核 bundle
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-review
```
如果你已经切到 Ops Center 页面,也可以直接看:
- 首屏 `总检决策`
- `总检主决策详情`
- API `GET /api/v1/ops/doctor-decision`
- 首屏 `交付证据`
- `交付证据详情`
- API `GET /api/v1/ops/go-live-bundle`
- 首屏 `正式复核`
- `正式复核详情`
- API `GET /api/v1/ops/go-live-review`
记录结果:
- `status`
- `headline`
- `critical_failures`
- `noncritical_failures`
- `launchpad_alignment.consistent`
- `env_audit.status`
- `env_audit.missing_items`
- `recommended_next_steps`
通过标准建议:
- `status=ready`
- 可进入最终人工确认或正式发布
- `status=attention`
- 核心报告已齐,但仍需复核补充失败项或环境缺口
- 也包括 `go_live_summary / stack_diagnosis / driver_feed / codex_brief` 的 launchpad 摘要出现不一致
- `status=blocked`
- 关键报告缺失,或环境审计已经判定阻断,不应直接宣称收口完成
如果 `env_audit.missing_items` 里出现:
- `missing_env:/etc/default/domaincheck-node-agent`
则这次 bundle review 已经不是泛泛地提示“环境缺口”,而是明确指向 Node Agent 接管还未收口。此时按下面顺序推进:
1. `agent-gap-export`
2. `node-bootstrap-plan`
3. 如果 summary 已提示 `runtime_may_need_restart=true`
4. 完成恢复后重新导出 bundle再做一次 `go-live-review`
### 3. 生成最终交付包
运行验证、bundle 复核都通过后,再生成最终交付包。
如果当前机器已经具备 smoke 运行条件,直接执行:
```bash
bash ./prepare_final_release.sh
```
如果当前机器只适合先做离线打包,可先跳过 smoke
```bash
DOMAINCHECK_SKIP_SMOKE_TEST=1 bash ./package_domain_release.sh
bash ./verify_domain_release.sh
```
后续再回到具备运行条件的机器上执行:
```bash
bash ./prepare_final_release.sh
```
最后统一查看最新交付结果:
```bash
bash ./show_latest_release.sh
```
重点只看:
- `latest_release.package_name`
- `latest_release.archive_path`
- `latest_release.sha256`
- `latest_release.smoke_test_ok`
- `final_release_ok`
- `final_release_report`
- `final_release_report_ok`
- `final_release_report_matches_latest`
- `final_release_report_stale_reason`
- `final_release_gate_decision`
- `final_release_gate_blocked_reasons`
- `final_release_gate_verify_ok`
- `final_release_gate_smoke_test_ok`
通过标准:
- `verify_domain_release.sh` 返回 `ok=true`
- `latest_release.smoke_test_ok=true`
- `final_release_ok=true`
- `final_release_report_matches_latest=true`
- `final_release_gate_decision=ready`
- `final_release_gate_verify_ok=true`
- `final_release_gate_smoke_test_ok=true`
- `final_release_report` 已指向最新一轮生成的正式报告
4. 先执行 `runtime-refresh-recover`
5. 再重新导出 bootstrap plan
---
## 四、最终交付结论模板
下面这段可以直接作为正式发布前的交付结论模板使用。
### 模板正文
```text
本轮发布前运行验证已完成。
一、统一收口结论
- go_live_status: <填写>
- publish_status: <填写>
- stack_status: <填写>
- automation_coverage.launch_status: <填写>
- launchpad_status: <填写>
二、默认下一步
- next_step_action_code: <填写>
- operator_title: <填写>
- launchpad_recommended_target_node_code: <填写>
- launchpad_recommended_recovery_label: <填写>
三、上线证据包
- bundle 路径: <填写>
- manifest 复核状态: <填写 ready/attention/blocked>
- go-live-review.headline: <填写>
- manifest.review_status_hint: <填写>
- critical_failures: <填写>
- noncritical_failures: <填写>
- manifest.launchpad_recommended_target_node_code: <填写>
- manifest.launchpad_recommended_recovery_label: <填写>
- manifest.launchpad_onboarding_bootstrap_pending_nodes: <填写>
- manifest.launchpad_onboarding_acceptance_ready_nodes: <填写>
- manifest.launchpad_alignment.consistent: <填写 true/false>
四、结论
- <填写:可进入正式发布 / 仍需继续收口 / 暂不可发布>
```
### 模板补充说明
填写“可进入正式发布”前,建议再做一次人工交叉确认:
- 发布门禁是否为 `ready` 或至少非 `blocked`
- 当前主车道是否已经明确
- 是否还存在 `dead_letter`
- 是否还有节点停留在 `bootstrap pending / acceptance pending`
- 是否已经保留可复盘的证据包与 manifest
---
## 五、交付给值班同事时最少要带什么
最少带下面 4 样:
1. `go-live-check` 摘要
2. `stack-diagnosis` 结果
3. `driver-feed / codex-brief` 结果
4. `go-live-export` 生成的 `manifest.json`
如果值班同事需要直接接手节点问题,再多带 3 样:
1. `node-acceptance-run` 最近结果
2. `log-sync-check` 最近结果
3. `queue-status``queue-records dead_letter` 最近结果
这样交班的人不需要重新从零拼现场。
---
## 六、真正的收工标准
如果要算“这次版本已经可以收工”,建议至少同时满足:
- 前端构建成功
- 海外单脑驾驶舱首屏状态正常
- `go-live-review.status != blocked`
- 发布门禁不为 `blocked`
- Node Agent 目标节点已完成接管验收
- 远端日志回传链可用或已确认本轮不依赖
- delivery queue 不存在未处理 `dead_letter`
- 当前默认下一步已经不是“继续补基础设施”,而是进入正式发布 / 观察 / 验收车道
到这一步,才适合说:
> 当前项目已经进入可上线、可交付、可持续运维状态。

287
docs/base.md Normal file
View File

@@ -0,0 +1,287 @@
# 主线任务验收总表
更新时间2026-04-21
## 当前执行原则
当前先只做一件事:
- 跑通主任务流程
- 把 7 个大任务按“可测试、可验收”的标准推进
- 并发、代理、展示层、CPU 打满这类细节优化先封存,不再抢主线
当前不再把“性能抠点”当主目标。
后续额度恢复后,再继续做细节优化专项。
## 当前主线优先级
按下面顺序推进,不跳步:
1. 大任务 1 真实验收闭环
2. 大任务 2 controller 编排闭环
3. 大任务 3 统一结果状态机闭环
4. 大任务 4 本地控制状态 + syncer/finalizer 闭环
5. 大任务 5 固定 worker pool + 持续补位替换旧模型
6. 大任务 6 时光机一期接入标准步骤
7. 大任务 7 运营视角指标面板落地
## 7 个大任务当前状态
### 大任务 1
单步骤任务底座落地
目标:
先打通 `controller -> queue -> claim -> worker -> result -> controller` 的完整闭环。
当前状态:
- 已有较完整代码底座
- `single_step` / `step_code` 模型已基本成形
- 现在缺的是“真实运行验收”而不是继续堆骨架
本任务验收只认下面 5 件事:
1. controller 能生成 `baidu_check` 任务
2. worker 能拉到 `baidu_check` 任务并执行
3. worker 能回传标准化结果
4. controller 能更新本地步骤状态
5. worker 超时未回传时,任务会回收重投
当前结论:
- 代码方向已基本对齐
- 2026-04-20 已完成一轮 live 验收打钩:
- `controller` 已生成 `single_step / detect_baidu_site` 任务(例:`job_id=6`, `job_code=step-20260420153527-9fc7b5`
- `worker` 已精准领取当前 `job_id` 并执行,不再被旧 `pipeline / sync / legacy fallback` 污染
- `worker` 已回传标准化结果到 `detect_job_items.result_payload_json`
- `controller` 已可按 `job_id` 定向执行 `process_pipeline`,并把结果落到本地 `domain_detections.baidu_site`
- “超时/遗留未回传”链路已验证会被节点启动释放并重新领取执行(`job_id=5` 在遗留 `running` 后被重新释放、重新领取并完成)
- 当前主线结论:大任务 1 已达到“可验收通过”状态,可以继续把主精力切到大任务 2 / 3
### 大任务 2
pipeline 编排器落地
目标:
把“下一步跑什么”彻底收回 controller。
当前状态:
- 基础方向已落到 controller 驱动
- 还需要继续做“按后台勾选顺序推进 / 按域名属性跳过”的真实验收
本任务必须确认:
- 同一个域名不会在 worker 里串完整条链
- controller 是唯一推进者
- 勾选顺序变化能影响下一步投递
- 跳过规则生效
当前结论:
- 已进入可验收阶段
- 2026-04-20 已补上关键收口:
- `single_step` 会话下worker 只按当前 `job_id` 领取任务
- `single_step` 会话下,旧的 `pipeline 推进 / sync pull / legacy fallback` 已被显式跳过
- `process_pipeline` 已支持按 `job_id` 定向处理,方便 controller 精准推进当前步骤
- 2026-04-20 又补完一轮 live 验收:
- `pass``detect_baidu_site` 完成后controller 已为同一 `job` 创建下一步 `detect_360_site`
- `skip`:一口价域名在 `detect_register + detect_baidu_site` 配置下,会直接解析到 `detect_baidu_site`
- 同时修掉了一个真实阻塞点:`process_pipeline()` 事务内再开第二连接写 `detect_run_events` 会把 controller 自己锁住;现已改成同事务同 cursor 写事件
- 当前主线结论:大任务 2 的 controller 编排主干已可验收,剩下更多是扩步骤和补更细跳过规则
### 大任务 3
步骤结果判定与重试策略落地
目标:
统一 `pass / retry / black_hit / reject`
当前状态:
- 结果结构、重试入口、黑名单终止方向已基本进入主链
- 还需要补 live 验收,重点是 TTL 回收、重投、终止规则
本任务必须确认:
- 外部失败会重投当前步骤
- 黑名单命中会终止后续步骤
- 非黑名单业务不通过按规则终止
- 不会出现同一步无限重试
当前结论:
- 代码已明显推进
- 2026-04-20 已完成 controller 侧 live 验收:
- `retry``state=degraded` 会重投当前步骤,不推进下一步
- `black_hit``state=blacklisted` 会终止后续步骤并结束当前 job
- `reject``state=rejected` 会终止当前流程,不再重试
- worker 侧也已补上业务失败 -> `rejected` 的结果态,不再把业务不通过和技术失败都混成 `failed`
- 当前主线结论:大任务 3 的统一结果状态机已基本闭环,可继续往大任务 4 / 5 推进
### 大任务 4
本地控制状态与海外主库同步落地
目标:
controller 本地维护高频状态syncer 批量同步海外主库finalizer 标记流程完成。
当前状态:
- 本地状态和部分同步链路已经在跑
- 已补上“最近完成任务快照也继续产出结果投影”
- 已补上结果导入后按 job_code 优先定位本地 job并刷新本地 job 收尾状态
- syncer/finalizer 还缺少一轮 live 闭环验收
本任务必须确认:
- 高频链路不依赖 worker 频繁直写海外主库
- controller 本地状态完整
- 批量同步成功
- 流程完成状态准确
当前结论:
- 代码主链已进一步收口
- 2026-04-21 已确认 `detect_result_projection / runtime_projection``detect_sync_records` 中持续产出且状态为 `projected`
- 当前说明 syncer 主链已恢复,但“本地 job 收尾状态 + 主库最终账本完全一致”的终验还需要继续盯现场
### 大任务 5
worker 池化与持续补位调度落地
目标:
真正替掉“批量认领 + 批量等待”的旧模型。
当前状态:
- 已经做了多轮并发热路径优化
- 已进一步压缩 executor 内部 backlog补位更接近固定槽位模型
- 但还需要一轮 live 运行观察 claimed/running 曲线,确认旧的批量认领惯性已被压住
本任务必须确认:
- 活跃槽位稳定贴近配置上限
- 并发不再大起大落
- 吞吐明显提升
- 调度器自耗下降
当前结论:
- 这是主线里仍然偏重的未完项
- 2026-04-21 已继续做现场修正:
- `claim_detect_job_items()` 已显式排除空 `step_code` 的 legacy 项,避免 worker 从标准队列入口继续误吞旧 whole-domain 项
- `mainland-controller-01 / 121.204.244.188``mainland-worker-01 / 121.204.244.248` 均已确认在真大陆节点参与执行
- 海外控制面 `queue_health / dashboard` 已补上“读取大陆 runtime/debug 近窗执行流”的兜底口径
- 当前首页已能看到真实近窗吞吐,例如 `10-15 项/分钟` 量级、并能拆到 controller/worker 两个节点
- 当前主线判断:
- “高 claimed 假活跃”问题已继续缓解
- “活吞吐不可见”问题已明显改善
- 但“总 completed 账本持续增长”和“running 贴近线程上限”仍未彻底验收,所以大任务 5 仍未签字通过
### 大任务 6
时光机一期流程落地
目标:
时光机按“最近 5 年”方案接成标准步骤任务。
当前状态:
- 现有项目里已有时光机相关检测逻辑
- 但还没有完全按标准步骤任务方式接进新 pipeline 验收
本任务必须确认:
- wayback 作为标准步骤任务接入
- 最近 5 年快照策略稳定
- 返回标准化结果
- controller 能把它当普通步骤推进/终止
当前结论:
- 2026-04-21 已落代码并通过测试:
- `detect_wayback` 已作为标准 `single_step` 步骤接入 controller / worker 主链
- 时光机一期已按“最近 5 年 + 命中即停”策略落地到 payload 和 detector
- 焦点测试已通过
- 但还缺 live 现场验收:
- 真实任务投递
- worker 执行
- 标准化结果回传
- controller 按普通步骤推进/终止
- 当前主线结论:大任务 6 已进入“代码落地完成、待现场验收”状态
### 大任务 7
运营视角指标与验收面板落地
目标:
让后台能判断“有没有跑起来、卡在哪一步、多久跑完”。
当前状态:
- 后端已有部分 runtime / detect status / debug event 统计基础
- 但完整的运营视角指标面板还没有完全落地验收
本任务必须确认:
- 每步骤队列数
- 每步骤吞吐
- 每分钟完成量
- 当前 pipeline 分布
- 重试数 / 黑名单数 / 失败数
- 预估剩余时间
当前结论:
- 2026-04-21 已落地首页最小运营面板,并补了第二层口径修正:
- `completed / pending / running` 已切到“全活跃任务累计口径”
- `步骤队列 / 节点吞吐 / 重试压力 / 有效执行节点` 已可直接展示
- `ETA` 在无真实近窗完成量时会显示“待计算”,避免误报 0 小时
- 2026-04-21 又补上“大陆 runtime/debug 近窗执行流”兜底:
- `active_job` 已可显示 `runtime_job_code`
- `processed_per_minute / completed_recent / node_throughput / step_queue` 已能贴近大陆真实执行
- 首页已能直接区分 `db_job_code``runtime_job_code`
- 当前结论:大任务 7 已进入“可运营分析并能指导现场排障”阶段,但仍需继续把“总 completed 账本”和“最终验收面板”完全统一
## 现在只做什么
当前只盯主线,不跑偏:
1. 把大任务 1 做成可真实验收
2. 验收过后立刻推进大任务 2
3. 再按顺序推进 3、4、5、6、7
如果某个问题只是:
- CPU 没吃满
- 某个 timeout 还能再抠
- 代理池还能更激进
- 页面还能再改得更好看
都先不打断主线。
## 已封存的细节优化 backlog
下面这些不是不做,而是先封存:
### A. 并发/调度优化
- 固定 worker pool 彻底替换旧批量认领模型
- claimed 回弹继续压缩
- executor 内部排队继续收紧
- 活跃 running 继续往上抬
- controller / worker 双节点吞吐平衡
### B. DB 往返优化
- 继续合并 `domains` 表高频更新
- 继续减少 `mark_running / finalize` 这类必要写库点开销
- 能走 Redis 或本地状态的尽量不走高频 DB
### C. 外部请求链路优化
- 代理失败后的重试链继续压缩
- 直连失败后回代理的等待窗口再收紧
- 无代理窗口等待策略再优化
- 外部请求 timeout 再按真实成功率调优
### D. 代理池策略优化
- 代理池刷新频率与补位策略继续增强
- 失败代理淘汰与新代理拉取节奏继续优化
- 控制“不过度预验证”和“不过度浪费线程”之间的平衡
### E. 运营展示层优化
- 更细的 runtime 面板
- ETA / 每分钟吞吐更精细展示
- 日志窗口布局继续优化
- 非主线的页面交互增强
## 接下来执行口径
接下来统一按这个口径推进:
- 先验收主流程
- 再补主流程缺口
- 性能细节先记账,不抢主线
- 每做完一个大任务,就给出“是否验收通过”的明确结论
一句话定调:
当前阶段不是“继续无限抠并发”,而是“先把 7 个大任务按主线流程逐个打通并验收”。

49
docs/codex接手.md Normal file
View File

@@ -0,0 +1,49 @@
把下面这段直接发给新的 Codex 就行:
```text
接手这个项目,请先不要发散,也不要先动展示层。你先完整阅读并基于现状继续推进主线。
项目路径:
`/www/wwwroot/getDomain`
必须先看这几份文档:
1. `docs/ops_center_runtime/HANDOFF_20260420_1920.md`
2. `docs/base.md`
3. `docs/test.md`
这次接手的硬性要求:
1. 先以 `docs/ops_center_runtime/HANDOFF_20260420_1920.md` 为准建立上下文。
2. 不要把当前这台机器当成真正的 mainland controller。
3. 当前工作机是海外 12 核测试控制面,真正的 `mainland-controller-01` 是 `121.204.244.188`。
4. 不要再优先动页面、展示层、面板文案。
5. 不要用破坏性 git 命令,不要回滚现有脏工作区改动。
6. 新增或修改代码前,先确认你改的是主线瓶颈,而不是辅助功能。
当前已经确认的事实:
1. 真正的 `mainland-controller-01` 已重新对正。
2. controller 的 node-agent 身份上报已经修好,现在控制面里应显示:
- `agent_hostname = mainland-controller-01`
- `agent_ip = 121.204.244.188`
3. controller 远端发布链已经成功跑通过一次。
4. 当前真正吃任务的是 `mainland-controller-01`。
5. `mainland-worker-01` 目前是 agent 在线,但检测没有真正参与,现象是本地检测态里出现 `127.0.0.1:5432 connection refused`。
6. 当前主线已经不是“节点身份问题”,而是“真 controller 吞吐”和“worker 恢复”。
你接手后只做两条主线:
1. 恢复 `mainland-worker-01`,让它重新进入可参与检测状态。
2. 继续压 `mainland-controller-01` 的真实吞吐,只盯 `claimed -> running -> completed` 的推进,不回展示层。
你要避免的坑:
1. 不要再把本机当成 `mainland-controller-01`。
2. 不要优先用本机 Python service 入口直接造 deploy job优先通过运行中的 API HTTP 接口。
3. 不要把 `job 332` 这种“node-agent 重启自己导致状态未优雅回写”的现象直接误判为真正失败。
4. 不要跑偏到 UI、导出、日志窗口样式这些支线。
你开始后先做这三件事,再继续动手:
1. 复述你理解的当前真实环境拓扑。
2. 复述当前两条唯一主线任务。
3. 给出你准备先验证的 3 个现场指标,再开始执行。
目标只有一个:
先把主流程和真实并发跑起来,让 controller 真机和 worker 真正参与检测,再谈细节优化。
```

View File

@@ -0,0 +1,98 @@
# HANDOFF 2026-04-18 23:21
## 当前最高优先级
大陆节点接管闭环最小路径
原因:
- 当前控制面能力已基本足够
- 当前最大阻塞不是新功能,而是大陆两台还停在:
- `pending_bootstrap`
- `agent_pending`
- `SSH 未配置`
- 只要这条链路不闭合,项目就仍然停留在“主控骨架可用,但统一接管未落地”的状态
## 推荐模型与推理等级
推荐:
- `GPT-5.4`
- `high`
原因:
- 当前阶段重心是优先级判断、闭环收口、执行顺序压缩
- 需要稳定判断力,不适合降到偏快但更容易发散的配置
- 当前阶段也暂时不需要切到 `xhigh`
## 下一轮如果继续,第一步先做什么
下一轮必须先做:
1. 录入大陆两台节点的 SSH 信息
2. 复查 `nodes`
3. 逐台跑 `node-handover`
4. 逐台跑 `node-bootstrap-plan`
建议顺序:
- `mainland-controller-01`
- `mainland-worker-01`
推荐第一组动作:
```bash
bash domain-api/deploy/multi-region/drive_ops_center.sh node-bind-ssh http://127.0.0.1:8100 mainland-controller-01 <ssh_host> <ssh_user> 22
bash domain-api/deploy/multi-region/drive_ops_center.sh node-bind-ssh http://127.0.0.1:8100 mainland-worker-01 <ssh_host> <ssh_user> 22
bash domain-api/deploy/multi-region/drive_ops_center.sh nodes http://127.0.0.1:8100
bash domain-api/deploy/multi-region/drive_ops_center.sh node-handover http://127.0.0.1:8100 mainland-controller-01
bash domain-api/deploy/multi-region/drive_ops_center.sh node-bootstrap-plan http://127.0.0.1:8100 mainland-controller-01
```
## 当前不要做的事情
现在不要做:
- 扩写新的架构设计文档
- 新增页面
- 新增模块
- 继续增强控制面专题能力
- 扩大 Release Hub 范围
- 扩大 runbook / playbook 范围
- 做与大陆节点接管闭环无直接关系的功能开发
## 当前阶段边界
本次已完成:
- 阶段校准
- 闭环优先级重排
- 任务板初始化
- 状态板初始化
- handoff 生成
本次未进入:
- 任何新实现
- 任何新页面或新模块
- 任何新的控制面增强项
## 下一轮完成主批次后的预期
如果大陆两台顺利完成:
- SSH 纳管
- bootstrap
- acceptance
- `remote_access_ready=3/3`
则项目总体进度预计进入:
- `60%~65%` 的稳定上线准备区间
那时下一阶段才应该切到:
- 发布前总检
- 正式收口
- 上线证据导出

View File

@@ -0,0 +1,155 @@
# HANDOFF 2026-04-18 23:44
## 当前最高优先级
仍然是:大陆节点接管闭环最小路径
但当前阶段已经从“补 SSH 入口”切到:
- 修正大陆节点环境内容
- 让 bootstrap 真正可以落地执行
## 今晚已完成的步骤
已完成:
1. 录入 `mainland-controller-01` SSH 信息
2. 录入 `mainland-worker-01` SSH 信息
3. 复查 `ops/nodes`
4. 逐台执行 `node-handover`
5. 逐台生成并复核 `node-bootstrap-plan`
6. 复核:
- `go-live-summary`
- `ops/nodes`
- `release-launchpad`
7. 手工验证 controller SSH 登录可达
## 当前结果
当前指标:
- `ssh_ready = 2`
- `remote_access_ready = 3`
- 是否达到 `remote_access_ready = 3/3`:是
但 A1 仍未闭环,因为:
- `mainland-controller-01` 仍是 `pending_bootstrap`
- `mainland-worker-01` 仍是 `pending_bootstrap`
- 两台都还没有完成:
- `bootstrap`
- `register / heartbeat`
- `acceptance`
## 两台节点推进到哪一步
### mainland-controller-01
已推进到:
- SSH 已录入
- `node-handover` 已完成
- `node-bootstrap-plan` 已生成
- 手工 SSH 登录成功
- 尝试执行 bootstrap 片段
准确卡点:
- 远端缺少 node-agent 所需文件
- bootstrap 执行时报错:
- `bootstrap_node_agent.sh not found under known layouts`
- `Unit domaincheck-node-agent.service could not be found`
阻塞分类:
- 主阻塞:环境问题
- 次阻塞:权限 / 外部条件问题
- 当前控制面自动 SSH 执行器默认走密钥模式
- 今晚验证可用的是密码 SSH
### mainland-worker-01
已推进到:
- SSH 已录入
- `node-handover` 已完成
- `node-bootstrap-plan` 已生成
准确卡点:
- 与 controller 同类
- 远端缺少:
- `domain-api/app/node_agent.py`
- `domain-api/app/api/routes/ops_agent.py`
- `domain-api/app/services/ops_agent_service.py`
- `domain-api/deploy/systemd/domain-node-agent.service`
- `domain-api/deploy/multi-region/templates/domaincheck-node-agent.env.example`
阻塞分类:
- 主阻塞:环境问题
## 收口结论
今晚属于“有明显进展,但 A1 未闭环”的收口结果。
明确进展:
-`remote_access_ready = 1/3` 推进到了 `3/3`
- 两台大陆节点都已进入 `ssh_ready`
- handover 与 bootstrap plan 链路都已打通
明确未完成:
- 两台大陆节点仍未完成 bootstrap
- 因此还没有 register / heartbeat
- 也没有进入 acceptance
## 下一轮如果继续,第一步先做什么
下一轮先做的不是新功能,而是修正大陆节点环境。
最小动作:
1. 确认大陆两台代码目录由 `www` 用户更新到包含 node-agent 文件的最新版本
2. 确认以下文件在两台大陆节点都存在:
- `domain-api/app/node_agent.py`
- `domain-api/app/api/routes/ops_agent.py`
- `domain-api/app/services/ops_agent_service.py`
- `domain-api/deploy/systemd/domain-node-agent.service`
- `domain-api/deploy/multi-region/templates/domaincheck-node-agent.env.example`
3. 然后重新执行:
- `node-bootstrap-plan`
- `bootstrap`
- `acceptance`
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
## 现在不要做的事情
不要做:
- 新页面
- 新模块
- 控制面增强项
- 新架构文档扩写
- Candidate B2
- 为了解决今晚问题而扩展新的运维功能
## 明天需要你补充或操作的内容
你明天需要安排的最小动作是:
- 让大陆两台节点的仓库内容更新到当前控制面所需版本
- 并且注意:
- git / 代码更新应继续使用 `www`
- 不要用 `root` 跑 git
## 当前一句话状态
今晚已经把大陆两台从“未纳管 SSH”推进到“SSH 可执行、bootstrap plan 可生成”,但两台都卡在相同的环境缺口上:远端仓库缺 node-agent 运行文件,因此 A1 还差最后的 bootstrap / register / acceptance 收口。

View File

@@ -0,0 +1,138 @@
# HANDOFF 2026-04-19 00:07
## 当前最高优先级
唯一最高优先级:
- 完成 `mainland-controller-01` 的公网控制面重接入
原因:
- `mainland-worker-01` 已经接管成功
- `remote_access_ready = 3/3` 已达成
- 当前只剩 controller 一台仍处于 `pending_bootstrap`
## 本轮已完成的步骤
已完成:
1. 复核当前 `nodes / go-live-summary / release-launchpad`
2. 确认两台大陆节点都已拉到最新代码
3. 重新生成 controller / worker 的 bootstrap plan
4.`mainland-controller-01` 成功执行一次 bootstrap 落地
5.`mainland-worker-01` 使用公网控制面地址完成:
- bootstrap
- register
- heartbeat
6. 确认 `mainland-worker-01` 已变为:
- `agent_state = online_busy`
- `remote_access_state = hybrid_ready`
7.`mainland-worker-01` 发起接管后验收:
- `playbook_run_code = pbr-137e8b258b`
## 当前结果
当前摘要:
- `ssh_ready = 2`
- `agent_ready = 2`
- `remote_access_ready = 3/3`
- `pending_bootstrap = 1`
节点结果:
- `mainland-worker-01`
- 已接管成功
- 已开始 acceptance
- `mainland-controller-01`
- 仍未完成接管
- 当前是唯一剩余阻塞点
## 两台节点推进到哪一步
### mainland-worker-01
已推进到:
- SSH 已录入
- `node-handover` 已完成
- `node-bootstrap-plan` 已生成
- 使用公网控制面地址完成 bootstrap
- register / heartbeat 已建立
- 节点已进入:
- `online_busy`
- `hybrid_ready`
- acceptance 已发起
当前状态判断:
- 该节点已经不再属于接管主阻塞
### mainland-controller-01
已推进到:
- SSH 已录入
- `node-handover` 已完成
- `node-bootstrap-plan` 已生成
- 首次 bootstrap 已真正落地安装并启动 node-agent
准确卡点:
- 第一次写入的 `OPS_CONTROL_PLANE_BASE_URL` 是:
- `http://127.0.0.1:8100`
- 对远端大陆节点来说,这会指向它自己,而不是海外控制面
- 随后尝试把它改为公网控制面地址时SSH 握手被远端重置
阻塞分类:
- 主阻塞:外部条件 / 网络或权限问题
- 不是:
- 新功能缺失
- 代码目录缺文件
- Node Agent 主链路不可用
## 下一轮若继续,第一步先做什么
下一轮第一步只做这一件事:
-`mainland-controller-01` 成功执行“公网控制面地址版本”的 bootstrap 命令块
最小动作顺序:
1. 恢复 controller SSH 可执行窗口
2. 重新写入:
- `/etc/default/domaincheck-node-agent`
3. 确认其中:
- `OPS_CONTROL_PLANE_BASE_URL=http://152.53.37.118:8100`
4. 重启:
- `domaincheck-node-agent`
5. 回控制面确认 controller 建立 register / heartbeat
6. 对 controller 执行 acceptance
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
当前不建议切低模型的原因:
- 剩下的是收口型、多条件联动的现场问题
- 需要稳定地分辨代码、执行参数、SSH 状态和节点真实状态
## 现在不要做的事情
不要做:
- 新页面
- 新模块
- 控制面增强项
- 新架构文档扩写
- Candidate B2
- 任何与 controller 收口无直接关系的工作
## 一句话结论
今晚不是“要不要重装系统”的阶段,而是已经把大陆接管闭环收束到只剩一台 controller`worker-01` 已接管成功,`controller-01` 只差把 node-agent 正确指向海外公网控制面并完成一次成功回连。

View File

@@ -0,0 +1,151 @@
# HANDOFF 2026-04-19 00:30
## 当前最高优先级
唯一最高优先级:
- 完成 acceptance 与发布前证据收口
原因:
- A1 大陆节点接管闭环已经完成
- 当前 3 台节点都已在线
- 当前真正剩余的不是接管问题,而是:
- acceptance 还没全部收口
- playbook run 仍有排队 / attention
- log sync 仍是 partial
## 本轮已完成的步骤
已完成:
1. 复跑 `go-live-check`
2. 复跑 `stack-diagnosis`
3. 复跑 `release-launchpad`
4. 复核 `mainland-worker-01` acceptance run
- `pbr-137e8b258b`
5. 确认 `mainland-controller-01` 已成功进入:
- `online_busy`
- `hybrid_ready`
6. 确认全局摘要:
- `pending_bootstrap = 0`
- `agent_ready = 3`
- `remote_access_ready = 3`
## 当前结果
当前已经成立的事实:
- 大陆节点接管闭环已完成
- controller / worker 都已接管成功
- delivery queue 当前 3/3 健康
- 发布包与 release gate 已就绪
当前仍未收口的事实:
- `mainland-worker-01` acceptance run `pbr-137e8b258b`
- 仍是 `queued / running`
- `release-launchpad` 当前推荐动作:
- `run_acceptance`
- 推荐目标:
- `mainland-controller-01`
- `log_sync_state = partial_coverage`
- 未覆盖节点:
- `mainland-worker-01`
- `mainland-controller-01`
## 最新总检摘要
### go-live-summary
- `go_live_status = attention`
- `publish_status = attention`
- `publish_blocking_reasons = []`
- `next_step_action_code = focus_playbook_run`
说明:
- 当前不是硬阻断
- 但仍建议先把 playbook / acceptance 收口完再正式发版
### stack-diagnosis
- `surface_status = healthy`
- `automation_status = attention`
- `stack_status = attention`
- 当前主推荐动作:
- `focus_playbook_run`
说明:
- 接口面与 contract 面没有缺口
- 当前问题集中在运行编排层
### release-launchpad
- latest package 可用
- latest release `ready`
- default rollout gate `ready`
- 当前 launchpad 仍显示阻断,原因不是 bootstrap而是
- `Node Agent 已在线,可以直接跑 onboarding.acceptance 做标准接管验收。`
- 推荐命令:
- `bash domain-api/deploy/multi-region/drive_ops_center.sh node-acceptance-run http://127.0.0.1:8100 mainland-controller-01 cli`
## 下一轮若继续,第一步先做什么
下一轮第一步只做这一件事:
-`mainland-controller-01` 发起 acceptance
然后依次做:
1. 观察 `mainland-controller-01` acceptance run
2. 跟完 `mainland-worker-01` acceptance run `pbr-137e8b258b`
3. 复查 playbook runs 是否仍有 `focus_playbook_run`
4. 再复查 `go-live-summary / stack-diagnosis / release-launchpad`
5. 输出上线签收证据摘要
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 当前阶段是高耦合收口,不适合切低模型
- 需要稳定判断 acceptance、playbook、launchpad 和 go-live 之间的关联关系
## 现在不要做的事情
不要做:
- 新页面
- 新模块
- 控制面增强项
- 新架构文档扩写
- 接管之外的自动化扩展
- 在 acceptance 未收口前提前进入正式 Rollout
## 上线前证据摘要
已经具备的证据:
- 大陆节点接管完成
- 3 台节点均在线
- 发布包可用
- smoke test 通过
- final release gate 为 `ready`
- delivery queue 当前 3/3 健康
尚缺的证据:
- controller acceptance 完成结果
- worker acceptance 完成结果
- playbook run 队列收口结果
- log sync partial 覆盖问题的最终结论
## 一句话结论
项目已经从“接管闭环阶段”进入“上线前证据收口阶段”;当前真正拦在前面的,只剩 acceptance 与 playbook / log sync 这类运行证据,还不是代码能力问题。

View File

@@ -0,0 +1,119 @@
# HANDOFF 2026-04-19 00:35
## 当前最高优先级
唯一最高优先级:
- 跟完 acceptance run拿到可签收终态
原因:
- acceptance 已全部发起
- 当前接管不是问题
- 当前真正卡住的是 acceptance 与 playbook run 收口
## 本轮已完成的步骤
已完成:
1.`mainland-controller-01` 发起 acceptance
2. 复核 `mainland-worker-01` acceptance run `pbr-137e8b258b`
3. 复查:
- `go-live-summary`
- `stack-diagnosis`
- `release-launchpad`
4. 输出 acceptance 收口链判断
## 本轮执行摘要
### controller acceptance 结果
- `run_code = pbr-bfed43ea46`
- 当前状态:`running`
- 当前焦点:`health`
- 当前说明:
- `采集健康快照 当前处于排队中,建议先看事件和节点现场输出。`
### worker acceptance 结果
- `run_code = pbr-137e8b258b`
- 当前状态:`running`
- 当前焦点:`health`
- 当前说明:
- `采集健康快照 当前处于排队中,建议先看事件和节点现场输出。`
### go-live-summary 当前状态
- `go_live_status = attention`
- `publish_status = attention`
- `stack_status = attention`
- `launchpad_status = attention`
- `next_step_action_code = focus_playbook_run`
### stack-diagnosis 当前状态
- `surface_status = healthy`
- `automation_status = attention`
- `stack_status = attention`
- `issue_total = 2`
- `blocking_issue_total = 0`
- `next_step_action_code = focus_playbook_run`
### release-launchpad 当前推荐动作
- `status = blocked`
- `recommended_action_code = run_acceptance`
- `recommended_target_node_code = mainland-controller-01`
- 当前推荐摘要:
- `Node Agent 已在线,可以直接跑 onboarding.acceptance 做标准接管验收。`
### log_sync_state`
- 当前仍为:`partial_coverage`
- 未覆盖节点:
- `mainland-worker-01`
- `mainland-controller-01`
## 当前是否可上线签收
当前结论:
- 还不可上线签收
## 若仍不可签收,唯一剩余阻塞是什么
唯一剩余阻塞:
- acceptance playbook run 尚未完成,没有形成可签收终态
更具体地说:
- `pbr-bfed43ea46` 仍在运行
- `pbr-137e8b258b` 仍在运行
- 两条 run 都停在排队中的 `health` 步骤
当前没有出现明确失败,但也没有成功收口。
## 现在不要做的事情
不要做:
- 正式发布动作
- 新功能开发
- 新模块 / 新页面
- 任何与 acceptance 收口无关的实现
## 下一轮若继续,第一步先做什么
下一轮第一步只做:
- 再次检查 `pbr-bfed43ea46``pbr-137e8b258b` 是否进入终态
如果 acceptance 仍卡在排队:
- 只记录阻塞点、影响范围和建议下一步
- 不扩展实现来绕过阻塞
## 一句话结论
acceptance 收口链已经全部发起但两条验收编排都还停在队列中当前离上线签收只差“acceptance 形成终态证据”,不是差功能,不是差接管,也不是差发布包。

View File

@@ -0,0 +1,135 @@
# HANDOFF 2026-04-19 00:50 CST
## 本轮目标
只处理 acceptance 队列不消费问题,不扩功能,不新增页面或专题文档。
## 本轮完成
### 1. 定位并修复 acceptance 队列卡死
定位结果:
- 两台大陆节点都在持续请求 `/api/v1/ops/agent/pull?limit=1`
- 控制面收到请求,但 acceptance job 长时间停留在 `queued`
- 数据库中存在大量 `idle in transaction`
- 事务卡在:
- `UPDATE ops_job_steps ...`
- 随后又在新连接里 `INSERT INTO ops_job_events ...`
代码修复:
- 文件:
- [domain-api/app/services/ops_agent_service.py](/www/wwwroot/getDomain/domain-api/app/services/ops_agent_service.py)
- 修改点:
- `agent_pull_jobs`
- `agent_mark_job_started`
- `agent_complete_job`
- 修复方式:
-`append_ops_job_event(...)` 从事务内部移到 `conn.commit()` 之后执行
### 2. 补充最小回归测试
- 文件:
- [domain-api/tests/test_ops_agent_service.py](/www/wwwroot/getDomain/domain-api/tests/test_ops_agent_service.py)
- 新增测试:
- `test_agent_pull_jobs_commits_before_appending_event`
- `test_agent_mark_job_started_commits_before_appending_event`
- `test_agent_complete_job_commits_before_appending_event`
- 验证结果:
- `cd /www/wwwroot/getDomain/domain-api && /opt/domaincheck/domainCheck/.venv/bin/python -m unittest tests.test_ops_agent_service -q`
- `Ran 27 tests ... OK`
### 3. 运行态验证
- `domaincheck-api` 已完成强制切换到新版本进程
- 新进程:
- `MainPID = 614403`
- 运行态日志已确认:
- `job 36 / 41` 开始执行
- 已出现 `start / events / complete`
## 当前 acceptance 结果
### `mainland-worker-01`
- run:
- `pbr-137e8b258b`
- 当前状态:
- `attention`
- 结果:
- `4 success + 1 failed`
- 唯一失败步骤:
- `node_agent_logs`
- 失败原因:
- `No journal files were opened due to insufficient permissions`
### `mainland-controller-01`
- run:
- `pbr-bfed43ea46`
- 当前状态:
- `attention`
- 结果:
- `4 success + 1 failed`
- 唯一失败步骤:
- `node_agent_logs`
- 失败原因:
- `No journal files were opened due to insufficient permissions`
## 当前总检状态
`go-live-summary`
- `go_live_status = attention`
- `publish_status = attention`
- `stack_status = attention`
- `launchpad_status = attention`
- `log_sync_state = full_capture`
`stack-diagnosis`
- `surface_status = healthy`
- `automation_status = attention`
- `stack_status = attention`
- `issue_total = 1`
- `blocking_issue_total = 0`
## 当前最高优先级
唯一最高优先级:
- 修复远端 Node Agent 读取 `journalctl` 的权限
## 当前是否可上线签收
结论:
- 还不可上线签收
唯一剩余阻塞:
- 两条 acceptance run 都因为 `node_agent_logs` 权限不足而未全绿
## 下一轮若继续,必须先做什么
只做这一件事:
- 处理 `domaincheck-node-agent` 所在服务账号的 journal 读取权限
推荐最小方向:
- 让运行 Node Agent 的账号具备读取 systemd journal 的权限
- 然后重跑 acceptance或只补采失败日志步骤
## 现在不要做的事情
- 不要回退这次热修复
- 不要重新 bootstrap
- 不要重装大陆机器
- 不要扩控制面功能
- 不要进入正式发布
## 本轮一句话结论
接管主链已经打通acceptance 队列事务 bug 已修复;当前只剩远端 `journalctl` 权限问题,解决后即可继续冲刺上线签收。

View File

@@ -0,0 +1,156 @@
# HANDOFF 2026-04-19 01:01
## 当前最高优先级
唯一最高优先级:
- 完成 `B2-Journal Permission Closure`
原因:
- 接管链路已经闭合
- acceptance 队列不消费问题已经修复
- 当前两条 acceptance run 只剩同一个失败步骤:
- `node_agent_logs`
## 本轮处理结论
本轮没有继续扩展控制面,也没有新增页面或模块。
本轮只做了两件事:
1. 把剩余阻塞进一步收敛为明确的环境落点:
- `domaincheck-node-agent.service``www:www` 运行
- 现网 unit 没有给 `www``journalctl` 所需的读取权限
2. 在仓库中的 Node Agent systemd 模板加入:
- `SupplementaryGroups=systemd-journal`
文件变更:
- `domain-api/deploy/systemd/domain-node-agent.service`
## 当前状态
当前摘要:
- `pending_bootstrap = 0`
- `agent_ready = 3`
- `remote_access_ready = 3`
- `managed_enabled = 3`
- `log_sync_state = full_capture`
acceptance 摘要:
- `mainland-worker-01`
- `run_code = pbr-137e8b258b`
- `status = attention`
- `4 success + 1 failed`
- 唯一失败步骤:`node_agent_logs`
- `mainland-controller-01`
- `run_code = pbr-bfed43ea46`
- `status = attention`
- `4 success + 1 failed`
- 唯一失败步骤:`node_agent_logs`
## 当前唯一剩余阻塞
唯一剩余阻塞:
- 两台大陆节点尚未刷新新的 Node Agent systemd unit
准确卡点:
- 代码仓库里已经补了 `SupplementaryGroups=systemd-journal`
- 但远端节点上的 `/etc/systemd/system/domaincheck-node-agent.service` 还需要重新安装并重启服务
阻塞分类:
- 环境 / 权限问题
不是以下问题:
- 不是 SSH 问题
- 不是 agent offline
- 不是 acceptance 队列不消费
- 不是控制面接口 404
## 下一轮若继续,第一步先做什么
下一轮第一步只做这一件事:
-`mainland-controller-01``mainland-worker-01` 上重新安装最新 Node Agent unit并重启 `domaincheck-node-agent`
然后依次做:
1. 确认 unit 已带 `SupplementaryGroups=systemd-journal`
2. 重跑两台节点 acceptance
3. 复核:
- `go-live-summary`
- `stack-diagnosis`
- `release-launchpad`
4. 输出上线签收证据摘要
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 当前阶段是最后一段 acceptance 收口
- 需要稳定处理运行证据与状态对账
- 不需要切到超高推理
## 现在不要做的事情
不要做:
- 新功能
- 新页面
- 新模块
- 控制面增强项
- 新专题文档
- 正式发布动作
## 给用户的下一任务卡片
按下面这张任务卡,在两台大陆节点执行:
```text
任务名B2-Journal Permission Closure / 节点 Unit 刷新
目标:
1. 让 domaincheck-node-agent 具备 journal 读取权限
2. 为 acceptance 清掉 node_agent_logs 的最后失败点
执行节点:
- mainland-controller-01
- mainland-worker-01
执行步骤:
1. 进入最新代码目录
2. 重新安装最新 unit 文件到 /etc/systemd/system/domaincheck-node-agent.service
3. daemon-reload
4. restart domaincheck-node-agent
5. 输出 unit 关键行与服务状态
执行命令:
cd /www/wwwroot/getDomain
install -m 0644 domain-api/deploy/systemd/domain-node-agent.service /etc/systemd/system/domaincheck-node-agent.service
systemctl daemon-reload
systemctl restart domaincheck-node-agent
systemctl cat domaincheck-node-agent | grep -E '^(User|Group|SupplementaryGroups)='
systemctl status domaincheck-node-agent --no-pager -l
journalctl -u domaincheck-node-agent -n 60 --no-pager
回传给 Codex 的结果:
1. systemctl cat 中是否出现 SupplementaryGroups=systemd-journal
2. systemctl status 是否 active (running)
3. journalctl 是否还出现 insufficient permissions
```
## 一句话结论
项目现在不缺接管能力,也不缺控制面能力;真正剩下的只是把两台大陆节点上的 Node Agent unit 刷新到最新,然后重跑 acceptance 把最后一个 `node_agent_logs` 失败点清掉。

View File

@@ -0,0 +1,126 @@
# HANDOFF 2026-04-19 01:07
## 当前最高优先级
唯一最高优先级:
- 执行 `C1-Acceptance Re-run`
原因:
- `B2-Journal Permission Closure` 在运行态上已经具备完成证据
- 两台节点都已出现:
- `logs.collect ok=True`
- `domaincheck-node-agent` 重启成功
- `registered: Agent 注册成功`
- 当前只剩旧 acceptance 结果尚未被新运行态覆盖
## 本轮确认到的运行态证据
`mainland-controller-01`
- 旧执行记录中已经出现:
- `action=logs.collect ok=True`
- 之后又完成:
- `domaincheck-node-agent.service` 停止 / 启动
- `starting node agent`
- `registered: Agent 注册成功`
`mainland-worker-01`
- 旧执行记录中已经出现:
- `action=logs.collect ok=True`
- 之后也完成:
- `domaincheck-node-agent.service` 停止 / 启动
- `starting node agent`
- `registered: Agent 注册成功`
## 当前判断
当前可以做出的最小结论:
- 日志权限收口在运行面已经打通
- Node Agent 当前在线且能重新注册
- 不需要再回头排查 SSH、bootstrap、heartbeat、队列消费
当前还不能直接签收上线的唯一原因:
- 控制面上仍保留旧 acceptance run 的 `attention` 结果
## 下一轮若继续,第一步先做什么
下一轮第一步只做这一件事:
- 分别对 `mainland-controller-01``mainland-worker-01` 重跑 acceptance
然后依次做:
1. 记录新的 acceptance `run_code`
2. 确认两条 run 是否全绿
3. 复核:
- `go-live-summary`
- `stack-diagnosis`
- `release-launchpad`
4. 输出上线签收证据摘要
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 当前还是高耦合收口阶段
- 但已经不需要切超高推理
## 现在不要做的事情
不要做:
- 新功能
- 新页面
- 新模块
- 控制面增强项
- 新专题文档
- 正式发布动作
## 给用户的下一任务卡片
按下面这张任务卡继续:
```text
任务名C1-Acceptance Re-run / 两台大陆节点验收重跑
目标:
1. 用新的运行态覆盖旧 acceptance 失败结果
2. 确认 mainland-controller-01 与 mainland-worker-01 是否都已通过标准接管验收
3. 为上线签收准备最终证据
执行位置:
- 海外控制面主机
执行命令:
cd /www/wwwroot/getDomain
bash domain-api/deploy/multi-region/drive_ops_center.sh node-acceptance-run http://127.0.0.1:8100 mainland-controller-01 cli
bash domain-api/deploy/multi-region/drive_ops_center.sh node-acceptance-run http://127.0.0.1:8100 mainland-worker-01 cli
然后继续执行:
curl -s http://127.0.0.1:8100/api/v1/ops/go-live-summary
echo
curl -s http://127.0.0.1:8100/api/v1/ops/stack-diagnosis
echo
curl -s http://127.0.0.1:8100/api/v1/ops/release-launchpad
回传给 Codex 的结果:
1. controller 新的 acceptance run_code 和最终状态
2. worker 新的 acceptance run_code 和最终状态
3. go-live-summary 当前状态
4. stack-diagnosis 当前状态
5. release-launchpad 当前推荐动作
```
## 一句话结论
当前项目已经越过“日志权限修复”这一步,下一步不需要再修环境,只需要把两台大陆节点的 acceptance 重跑一遍,用新结果完成上线前签收判断。

View File

@@ -0,0 +1,133 @@
# HANDOFF 2026-04-19 01:15
## 当前最高优先级
唯一最高优先级:
- 执行 `D1-Evidence Convergence`
原因:
- 大陆两台 acceptance 已经全绿
- 当前不再是接管链路问题
- 当前剩余的是“上线签收证据口径”没有完全收敛
## 本轮已完成
`mainland-controller-01`
- acceptance 新 run
- `pbr-9ce5c85f17`
- 最终结果:
- `status = success`
- `5 success / 0 failed`
`mainland-worker-01`
- acceptance 新 run
- `pbr-389abd618c`
- 最终结果:
- `status = success`
- `5 success / 0 failed`
总检现状:
- `go_live_status = attention`
- `stack_status = attention`
- `publish_status = attention`
- `launchpad_status = attention`
- `log_sync_state = partial_coverage`
- `log_sync_missing_node_codes = [overseas-control-01]`
- `stack_diagnosis.issue_total = 2`
- `stack_diagnosis.blocking_issue_total = 0`
## 当前判断
当前已经可以确认:
- 大陆节点接管闭环已完成
- acceptance 已通过
- Node Agent 日志权限问题已真实解除
当前还不能直接签收上线的原因只有一类:
- 证据口径还没完全收敛
具体表现为两处:
- `overseas-control-01` 还没有补齐日志样本,导致 `log_sync_state = partial_coverage`
- `stack-diagnosis / release-launchpad` 仍保留历史 attention / stale 推荐
## 下一轮若继续,第一步先做什么
下一轮第一步只做这一件事:
-`overseas-control-01` 补一轮场景日志样本
然后依次做:
1. 复查 `go-live-summary`
2. 复查 `stack-diagnosis`
3. 复查 `release-launchpad`
4. 判断 attention 是否已收敛到可上线签收
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 当前还是收口判断阶段
- 需要稳定地辨别“真实阻塞”和“口径残留”
- 但还不需要切到超高推理
## 现在不要做的事情
不要做:
- 新功能
- 新页面
- 新模块
- 控制面增强项
- 新专题文档
- 正式发布动作
## 下一个任务卡
```text
任务名D1-Evidence Convergence / overseas-control-01 日志补样与总检复核
目标:
1. 补齐 overseas-control-01 的场景日志样本
2. 观察 go-live-summary 是否从 partial_coverage 收敛
3. 观察 stack-diagnosis 与 release-launchpad 是否仍保留历史残留口径
4. 判断是否达到可上线签收状态
执行位置:
- 海外控制面主机
执行命令:
cd /www/wwwroot/getDomain
bash domain-api/deploy/multi-region/drive_ops_center.sh scene-node-log http://127.0.0.1:8100 overseas-control-01 120 full
然后继续执行:
curl -s http://127.0.0.1:8100/api/v1/ops/go-live-summary
echo
curl -s http://127.0.0.1:8100/api/v1/ops/stack-diagnosis
echo
curl -s http://127.0.0.1:8100/api/v1/ops/releases/launchpad
回传给 Codex 的结果:
1. overseas-control-01 场景日志是否成功拉到样本
2. go-live-summary 当前状态
3. stack-diagnosis 当前 issue_total / blocking_issue_total
4. release-launchpad 当前推荐动作
5. 当前是否已经达到可上线签收
```
## 一句话结论
acceptance 这一关已经过了;下一轮不该再回头修大陆节点,而是只把 `overseas-control-01` 的日志样本和总检残留口径收敛掉。

View File

@@ -0,0 +1,128 @@
# HANDOFF 2026-04-19 01:21
## 当前最高优先级
唯一最高优先级:
- 执行 `E1-Historical Signal Convergence`
原因:
- `overseas-control-01` 的日志样本已经补齐
- `go-live-summary.log_sync_state` 已恢复为 `full_capture`
- 当前不再是样本缺口问题,而是历史 attention 口径未完全收敛
## 本轮已完成
日志样本补齐:
- 已执行 `log-sync-recover`
- 已执行 `run_inspection_participating`
- 新巡检 run
- `pbr-df533c6f4a`
- `overseas-control-01`
- `scene-log status = full_capture`
- `line_count = 1`
总检变化:
- `go-live-summary`
- `log_sync_state: partial_coverage -> full_capture`
- `log_sync_missing_node_codes: [overseas-control-01] -> []`
- `stack-diagnosis`
- `issue_total: 2 -> 1`
- `blocking_issue_total = 0`
- `playbook_runs.problem_runs_total`
- `4 -> 3`
## 当前判断
当前已经可以确认:
- 大陆节点接管闭环已完成
- acceptance 已通过
- participating 节点日志样本覆盖已完成
当前还不能直接签收上线的原因只有一类:
- 历史 playbook / launchpad attention 口径还没完全消化掉
具体表现为两处:
- `stack-diagnosis` 还剩:
- `playbook_runs_need_attention`
- `release-launchpad` 还保留旧推荐:
- `run_acceptance`
- `mainland-controller-01`
## 下一轮若继续,第一步先做什么
下一轮第一步只做这一件事:
- 聚焦 `focus_playbook_run`
然后依次做:
1. 查清 `problem_runs_total = 3` 是不是纯历史旧 run
2. 复查 `stack-diagnosis`
3. 复查 `release-launchpad`
4. 判断当前是否已经达到可上线签收
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 当前已经进入最后的收口判断阶段
- 需要高质量区分“真阻塞”和“历史口径残留”
- 还不需要切超高推理
## 现在不要做的事情
不要做:
- 新功能
- 新页面
- 新模块
- 控制面增强项
- 新专题文档
- 正式发布动作
## 下一个任务卡
```text
任务名E1-Historical Signal Convergence / 历史 playbook attention 收口
目标:
1. 确认 stack-diagnosis 剩余的唯一告警是不是纯历史旧 run
2. 判断 release-launchpad 的旧 acceptance 推荐是否只是残留口径
3. 为上线签收做最后判断
执行位置:
- 海外控制面主机
执行命令:
cd /www/wwwroot/getDomain
bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 focus_playbook_run
echo
bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 open_playbook_run_latest_events
echo
curl -s http://127.0.0.1:8100/api/v1/ops/stack-diagnosis
echo
curl -s http://127.0.0.1:8100/api/v1/ops/releases/launchpad
回传给 Codex 的结果:
1. focus_playbook_run 指向的具体 run_code
2. 该 run 是否是历史旧 run
3. stack-diagnosis 当前 issue_total
4. release-launchpad 当前推荐动作
5. 当前是否已经达到可上线签收
```
## 一句话结论
日志样本缺口已经补上了;下一轮不该再碰接管和日志链路,而是只把最后那条历史 attention 口径清掉。

View File

@@ -0,0 +1,129 @@
# HANDOFF 2026-04-19 02:25
## 本轮完成了什么
本轮只收口了“大陆 controller 无法 `pull_tasks`”这一条链。
实际完成:
1. 修复 `domaincheck-node-agent` 读取不到同步目标地址的问题
2.`www` 提交并推送:
- `74dc009`
- `fix: inherit sync env in node agent`
3. 在两台大陆节点刷新 `domaincheck-node-agent.service`
4. 重启并验证:
- `mainland-controller-01`
- `mainland-worker-01`
5. 从海外控制面再次发起:
- `runtime.pull_tasks`
- `job_id = 87`
6. 验证 `mainland-controller-01` 返回成功:
- `pull_state = success`
- `items_total = 50`
7. 验证大陆两台节点当前都处于:
- `participation_state = running`
## 当前最高优先级
唯一最高优先级:
- 收敛检测总览统计口径
原因:
- 现在不是“没跑”
- 而是“已经跑了,但总览没完整体现大陆执行量”
## 当前状态摘要
当前结论:
- 检测执行链已跑通
- 大陆 controller 已能拉任务
- 大陆 controller / worker 已进入执行中
直接证据:
- `ops/nodes`
- `mainland-controller-01`
- `items_total = 200`
- `items_running = 5`
- `mainland-worker-01`
- `items_total = 70`
- `items_running = 5`
- `job 87`
- `runtime.pull_tasks`
- `status = success`
## 当前唯一剩余问题
唯一剩余问题:
- `detect/queue-summary`
- `detect/job/active`
仍主要沿用旧的海外活跃任务口径,没有把大陆“拉批后本地执行”的量体现在同一汇总里。
这会导致页面观感像“大陆没跑”,但实际上已经在跑。
## 下一轮如果继续,只做什么
下一轮只做这一件事:
- 对齐以下三处的数据口径:
- `ops/nodes`
- `detect/queue-summary`
- `detect/job/active`
目标:
- 让后台页面既能显示大陆节点正在执行
- 又能把这部分执行量合并进统一检测进度
## 现在不要做的事情
不要做:
- 新页面
- 新模块
- 运维中枢增强
- 正式发布
- 与检测总览收口无关的任何工作
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 当前是数据口径排查与小范围实现
- 不需要切超高
## 给下一轮的任务卡
```text
任务名G1-检测总览口径统一批
目标:
1. 查清 ops/nodes 与 detect/job/active 的数据来源差异
2. 明确大陆 controller 拉批执行为什么没有进入统一检测总览
3. 修好后再跑一轮小批量检测验证
范围限制:
1. 只做检测总览口径统一
2. 不新增页面
3. 不扩展控制面功能
4. 不进入发布动作
完成判定:
1. 点击启动检测后
2. 后台能看到大陆节点参与
3. detect/queue-summary 不再只显示 overseas-control-01 与 unassigned
```
## 一句话结论
这轮已经把“大陆 controller 拉不到任务”这个硬阻塞清掉了;现在真正剩下的不是执行问题,而是后台统计口径还没把大陆执行量完整显示出来。

View File

@@ -0,0 +1,122 @@
# HANDOFF 2026-04-19 02:33
## 本轮完成了什么
本轮只处理了一个问题:
- Detect 页面没有把大陆节点参与展示出来
实际完成:
1. 后端补出分布式显示口径
2. 前端 Detect 页面切到优先显示分布式口径
3. 本地重启 `domaincheck-api`
4. 重新验证 Detect 接口
## 本轮关键结果
`detect/job/active` 现在新增:
- `distributed_node_stats`
- `display_items_claimed`
- `display_items_running`
当前接口结果:
- `display_items_claimed = 34`
- `display_items_running = 14`
当前已显示节点:
- `mainland-controller-01`
- `mainland-worker-01`
- `overseas-control-01`
- `unassigned`
`detect/queue-summary` 现在新增:
- `queue.display_claimed = 34`
- `queue.display_running = 14`
并且 `nodes` 已包含大陆 controller / worker。
## 当前最高优先级
唯一最高优先级:
- 检测账本统一
原因:
- 现在页面显示已经基本正常
- 剩下的不是“看不见”,而是“中央账本和分布式执行账本还没真正合并”
## 当前状态结论
当前可以明确说:
- 检测能跑
- 大陆节点确实参与了
- Detect 页面现在已经能直接看见大陆参与
## 当前唯一剩余问题
唯一剩余问题:
- 目前仍是双账本:
- 中央 `detect_job_items`
- 分布式 runtime / projection 显示口径
所以:
- 页面观感已收口
- 账本一致性还没完全收口
## 下一轮如果继续,只做什么
下一轮只做这一件事:
- 明确并实现“中央派发账本”与“大陆执行账本”的统一规则
优先原则:
- 不发散
- 不扩新页面
- 不碰发布动作
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 下一轮是账本统一策略与最小实现
- 仍不需要切超高
## 给下一轮的任务卡
```text
任务名H1-检测账本统一设计与最小落地批
目标:
1. 查清 detect_job_items 与 runtime/projection 的最终一致关系
2. 决定 pull / ack / result sync 后中央账本如何更新
3. 只做最小一致性修复,不扩功能
范围限制:
1. 不新增页面
2. 不扩控制面功能
3. 不进入发布动作
4. 不并行做别的方向
完成判定:
1. Detect 页面显示正确
2. Detect 中央账本与大陆执行账本不再明显分叉
```
## 一句话结论
这轮已经把“大陆在跑但页面像没跑”的问题收掉了;下一轮真正该做的,不是继续修显示,而是把检测账本本身统一起来。

View File

@@ -0,0 +1,127 @@
# HANDOFF 2026-04-19 02:40
## 本轮完成了什么
本轮只处理了一个问题:
- Detect 主统计还是“中央原值 + display 附加值”双轨Runtime / Detect 不够统一
实际完成:
1. 新增有效账本聚合逻辑
2. `active_job` 主字段切到统一后的有效值
3. 保留 `raw_*` 原始中央账本字段
4. 新增针对统一规则的后端单测
5. 重启 `domaincheck-api`
6. 重新验证线上接口
## 本轮关键结果
`detect/job/active` 现在主字段直接返回:
- `items_total = 1000`
- `items_pending = 931`
- `items_claimed = 34`
- `items_running = 14`
- `items_completed = 21`
同时保留原始中央账本:
- `raw_items_pending = 950`
- `raw_items_claimed = 25`
- `raw_items_running = 4`
`node_stats` / `distributed_node_stats` 当前已统一为:
- `mainland-controller-01`
- `mainland-worker-01`
- `overseas-control-01`
- `unassigned = 680`
`detect/queue-summary` 当前主字段:
- `pending = 931`
- `claimed = 34`
- `running = 14`
## 当前最高优先级
唯一最高优先级:
- 决定是否继续进入 item 级结果回写统一
原因:
- 当前主统计已经基本统一
- 剩下真正没闭环的是 `detect_result_projection -> detect_job_items`
## 当前状态结论
当前可以明确说:
- 检测能跑
- 大陆节点确实参与了
- Detect 页面和主统计都更接近真实执行态
- Runtime / Queue / Detect 主摘要开始吃同一套有效账本
## 当前唯一剩余问题
唯一剩余问题:
- 目前还是“聚合统一”
- 还不是“逐条 item 最终一致”
所以:
- 主观感受和主统计已经收口
- 底层逐条账本还没完全收口
## 下一轮如果继续,只做什么
下一轮只做这一件事:
- 查清是否要把 `detect_result_projection` 最小映射回 `detect_job_items`
优先原则:
- 不发散
- 不扩新页面
- 不碰发布动作
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 下一轮是 item 级账本映射策略
- 仍然是高复杂度,但还没到必须切超高
## 给下一轮的任务卡
```text
任务名I1-detect_result_projection 到 detect_job_items 的最小映射设计批
目标:
1. 查清当前 detect_result_projection 能提供哪些聚合字段
2. 判断是否足以做 item 级状态回写,还是只能做批次级回写
3. 只做最小一致性设计,不重做执行链
范围限制:
1. 不新增页面
2. 不扩控制面功能
3. 不进入发布动作
4. 不并行做别的方向
完成判定:
1. 给出 item 级统一是否可行的结论
2. 如果可行,明确最小落点
3. 如果暂不可行,明确缺的字段和最小补数方案
```
## 一句话结论
这轮已经把 Detect 主统计从“靠 display 补丁看懂”推进到“主字段直接统一可读”;下一轮真正该做的,只剩下是否继续把结果同步推进到 item 级逐条账本。

View File

@@ -0,0 +1,135 @@
# HANDOFF 2026-04-19 02:43
## 本轮完成了什么
本轮只做了一件事:
-`I1-检测结果逐条回写设计批` 查到底,确认当前是否真的能做 item 级统一
实际结论:
- 现在还不能直接做 item 级回写
## 本轮关键证据
### 证据 1`detect_result_projection` 只有聚合数据
当前只包含:
- `job`
- `latest_event`
- `queue`
- `phase`
没有:
- `domain_id`
- `job_item_id`
- 逐条终态结果
### 证据 2中央 `detect_run_events` 的逐条结果只有海外
当前中央看到的逐条事件只有:
- `overseas-control-01`
- `domain_started`
- `domain_completed`
中央没看到:
- `mainland-controller-01`
-`domain_*`
- `mainland-worker-01`
-`domain_*`
### 证据 3所以当前不能直接回写 `detect_job_items`
原因不是逻辑不会写,而是中央没有大陆逐条输入。
## 当前最高优先级
唯一最高优先级:
- `J1-大陆逐条结果同步前置批`
原因:
- item 级统一的真正阻塞点已经定位
- 下一步必须先把大陆逐条结果送到中央
## 当前状态结论
当前可以明确说:
- 检测能跑
- 大陆节点确实参与了
- 主统计已经统一
- 但 item 级回写现在还做不了
## 当前唯一剩余问题
唯一剩余问题:
- 大陆节点缺少逐条结果进入中央的最小同步通道
所以当前阶段已经从:
- “显示不对”
进入到:
- “逐条结果输入还没进中央”
## 下一轮如果继续,只做什么
下一轮只做这一件事:
- 给大陆执行链补最小逐条结果同步输入
优先原则:
- 不发散
- 不扩页面
- 不碰发布动作
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
原因:
- 下一轮是同步链最小设计与落地
- 还不必切超高
## 给下一轮的任务卡
```text
任务名J1-大陆逐条结果同步前置批
目标:
1. 让大陆节点把逐条检测终态送到中央
2. 至少带回:
- job_code
- cycle_token
- domain_id 或可稳定映射的 domain
- result_status
- finished_at
3. 只补输入通道,不做最终 item 回写
范围限制:
1. 不新增页面
2. 不扩控制面功能
3. 不进入发布动作
4. 不并行做别的方向
完成判定:
1. 中央能看到 mainland 节点的 domain_* 终态事件或等价逐条投影
2. 后续再做 detect_job_items 回写时,不再缺输入
```
## 一句话结论
这轮已经把“为什么 item 级统一还做不了”彻底查清了;下一轮真正该做的,不是继续改统计,而是先把大陆逐条结果送进中央。

View File

@@ -0,0 +1,97 @@
# HANDOFF 2026-04-19 02:51
## 本轮完成了什么
本轮只做了 `J1-大陆逐条结果同步前置批` 的最小实现,不进入新页面、不扩控制面:
- `detect_result_projection` 新增 `recent_domain_events`
- 中央 ingest `detect_result_projection` 时开始尝试把逐条事件写入 `detect_run_events`
- 增加了 `import_fingerprint` 去重
- 新增最小单测
- 已重启中央 `domaincheck-api`
## 已完成验证
已完成:
- `python3 -m py_compile`
- `python -m unittest tests.test_sync_record_service tests.test_sync_push_service`
- 中央 `domaincheck-api` 重启成功
## 当前真实状态
要区分两层:
### 1. 代码闭环
这一层已经补上:
- 大陆侧投影格式支持逐条事件
- 中央视角 ingest 支持把逐条事件落入 `detect_run_events`
### 2. 真实运行闭环
这一层还差最后一步:
- 大陆节点必须拉到最新代码
- 然后继续运行同步
- 中央才能真正看到 mainland `domain_*`
## 当前最高优先级
唯一最高优先级:
- 让大陆节点拉最新代码后,验证 `recent_domain_events -> central detect_run_events`
## 下一轮只做什么
下一轮只做以下最小动作:
1. 在大陆节点确认当前代码已是最新
2. 触发或等待新的 `detect_result_projection`
3. 检查中央最新 `detect_result_ingest.payload.projection.recent_domain_events`
4. 检查中央 `detect_run_events` 是否出现:
- `mainland-controller-01`
- `mainland-worker-01`
- 对应 `domain_started/domain_completed/domain_failed/domain_blacklisted`
## 下一轮不要做什么
继续不要做:
- 新页面
- 新模块
- 控制面增强
- 发布动作
- item 级最终回写
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
## 给下一轮的最小任务卡
```text
任务名J1-大陆逐条结果同步前置批(验证轮)
目标:
1. 确认大陆节点已拉到最新代码
2. 确认最新 detect_result_projection 已含 recent_domain_events
3. 确认中央 detect_run_events 已出现 mainland domain_* 事件
完成判定:
1. detect_result_ingest.payload.projection.recent_domain_events 非空
2. detect_run_events 中可查询到 mainland-controller-01 / mainland-worker-01 的 domain_* 事件
边界:
1. 不做 item 级回写
2. 不做新页面
3. 不做控制面扩展
```
## 一句话结论
这轮已经把“中央如何接并落大陆逐条事件”的代码闭环补上了;下一轮只差让大陆节点跑到这版代码并验证真实事件进中央。

View File

@@ -0,0 +1,66 @@
# HANDOFF 2026-04-19 02:57
## 本轮新增完成
在上一轮“中央可接收并落库逐条事件”基础上,这一轮又补了最后一个自动触发点:
- `app.sync_agent` 每个 tick 会自动产出 `detect_result_projection`
- 不再依赖有人去访问 mainland 检测页面
## 当前真实判断
当前看到的中央证据是:
- `mainland-controller-01` / `mainland-worker-01` 心跳正常
- `runtime_ingest.updated_at` 已刷新到 `2026-04-19 02:55:36`
- `detect_result_ingest.updated_at` 仍停留在 `2026-04-17 16:57:32`
- `detect_run_events` 里仍没有 mainland `domain_*`
这说明:
- mainland 同步链是活的
- 但 अभी还没有跑到“自动产 detect_result_projection”的新代码
## 这轮后的唯一剩余动作
现在只剩一个最小外部动作:
1. mainland 相关节点拉最新代码
2. 重启 `domaincheck-sync-agent`
建议最小命令:
```bash
systemctl restart domaincheck-sync-agent
sleep 3
systemctl status domaincheck-sync-agent --no-pager -l
journalctl -u domaincheck-sync-agent -n 80 --no-pager
```
如果 service 名不是这个,再按机器当前实际 service 名执行。
## 重启后我下一轮只查什么
下一轮只查这 3 件事:
1. 最新 `detect_result_ingest.payload.projection.recent_domain_events` 是否非空
2. `detect_run_events` 是否出现 mainland `domain_started/domain_completed/domain_failed/domain_blacklisted`
3. `detect/job/active``recent_events` 是否开始出现 imported mainland 逐条事件
## 继续不要做什么
- 不做 item 级最终回写
- 不做新页面
- 不做控制面增强
- 不做发布动作
## 推荐模型与推理等级
继续推荐:
- `GPT-5.4`
- `high`
## 一句话结论
现在代码链路已经补到“mainland 拉新并重启 sync agent 后就该自动把逐条结果送进中央”;下一轮只差验证真正贯通。

View File

@@ -0,0 +1,68 @@
# HANDOFF 2026-04-19 03:00
## 本轮做了什么
本轮没有进入新实现,只做了中央只读复查:
1. 复查 mainland `detect_result_ingest`
2. 复查 mainland `runtime_ingest`
3. 复查中央 `detect_run_events`
## 本轮结论
结论已经非常明确:
- mainland 同步链是活的
- 但 mainland 仍未真正跑到新版 `domaincheck-sync-agent`
## 证据
### 1. `runtime_ingest` 仍在刷新
- 最新 `updated_at``2026-04-19 02:59:12`
### 2. `detect_result_ingest` 没有刷新
- 最新 `updated_at` 仍停在 `2026-04-17 16:57:32`
### 3. mainland `domain_*` 仍为 0
- `detect_run_events`
- mainland `domain_started/domain_completed/domain_failed/domain_blacklisted`
- 当前 `count = 0`
## 当前唯一剩余动作
现在只剩一个外部动作:
1. mainland 节点拉最新代码
2. 重启 `domaincheck-sync-agent`
建议直接执行:
```bash
git pull
systemctl restart domaincheck-sync-agent
sleep 3
systemctl status domaincheck-sync-agent --no-pager -l
journalctl -u domaincheck-sync-agent -n 80 --no-pager
```
## 你执行完后,我下一轮只查什么
我下一轮只查这 3 个结果:
1. `detect_result_ingest.payload.projection.recent_domain_events` 是否非空
2. `detect_run_events` 是否出现 mainland `domain_*`
3. `detect/job/active``recent_events` 是否开始出现 imported mainland 逐条事件
## 继续不要做什么
- 不做 item 级最终回写
- 不做新页面
- 不做控制面增强
- 不做发布动作
## 一句话结论
现在代码已经补完,卡点不在中央,卡点只剩 mainland 端还没切到新版 `domaincheck-sync-agent`

View File

@@ -0,0 +1,96 @@
# HANDOFF 2026-04-19 03:08
## 本轮做了什么
本轮没有进入新实现,只做了最小链路核查:
1. 复查中央 `detect/job/active`
2. 复查中央 `ops/nodes`
3. 复查 `go-live-summary` / `stack-diagnosis` / `release-launchpad`
4. 复查最新 `onboarding.acceptance`
5. 通过远端 Agent 对 `mainland-controller-01` 执行:
- `service.status`
- `logs.collect`
目标服务:`domaincheck-sync-agent`
## 本轮结论
当前状态已经进一步推进:
- 检测任务在跑
- 节点接管在跑
- 最新 acceptance 已成功
- `mainland-controller-01``domaincheck-sync-agent` 已重启成功
- 重启后首轮已把 mainland 逐条结果推回中央
## 关键证据
### 1. 检测任务确实在跑
- 活跃任务:`detect-20260417170546-96023e`
- 参与节点:
- `mainland-worker-01`
- `mainland-controller-01`
- `overseas-control-01`
### 2. 最新 acceptance 已成功
- `pbr-9ce5c85f17`:成功
- `pbr-389abd618c`:成功
说明:
- 接管验收不再是当前唯一主阻塞
### 3. sync-agent 服务已重启到新进程
远端只读结果:
- 服务:`domaincheck-sync-agent`
- 状态:`active (running)`
- 启动时间:`2026-04-19 16:09:52 CST`
- 运行命令:
- `/opt/domaincheck/domainCheck/.venv/bin/python -m app.sync_agent`
### 4. 重启后首轮结果投影已推送成功
最新日志显示:
- `detect_result_projection`
- `batch_count = 1`
- `success_count = 1`
- `event_import.imported_count = 10`
### 5. 中央 mainland 逐条结果已出现
- 新增 `detect_result_ingest`
- `id = 5382`
- `created_at = 2026-04-19 03:10:14`
- 近期 mainland `domain_*`
- `count = 10`
## 下一轮唯一剩余动作
下一轮不要发散实现,只做持续性复查:
1. `/api/v1/runtime/sync-summary`
2. `/api/v1/detect/job/active`
3. mainland `domain_started/domain_completed/domain_failed/domain_blacklisted`
4. `/api/v1/ops/go-live-summary`
5. `/api/v1/ops/stack-diagnosis`
重点判断:
- mainland `domain_*` 是否持续增长
- 总检 attention 是否已主要退化为历史残留
## 继续不要做什么
- 不做新页面
- 不做控制面增强
- 不做发布动作
- 不做 item 级最终回写
## 一句话结论
`mainland-controller-01``domaincheck-sync-agent` 重启后,逐条结果同步已经打通;当前工作重点从“修链路”切换到“验证持续性与上线签收口径”。

View File

@@ -0,0 +1,128 @@
# HANDOFF 2026-04-19 03:18
## 本轮做了什么
本轮没有进入新实现,只做了运行态只读复查:
1. 对比一个完整 40 秒观察窗口前后的:
- `/api/v1/detect/job/active`
- `/api/v1/runtime/sync-summary`
2. 复查中央 `detect_run_events`
3. 复查:
- `/api/v1/ops/go-live-summary`
- `/api/v1/ops/stack-diagnosis`
- `/api/v1/ops/activity-stream`
4. 复查节点现场日志:
- `mainland-controller-01`
- `mainland-worker-01`
## 本轮结论
这轮结论要纠偏:
- 接管链路基本完成
- 同步链路已经打通过一次
- 但检测执行面当前没有继续出新结果
因此当前主阻塞不再是“接管/同步未通”,而是:
- 检测执行停滞
- 外部站点依赖或代理池可用性异常
## 关键证据
### 1. 三台节点都在参与,但近窗没有吞吐
活跃任务仍是:
- `detect-20260417170546-96023e`
参与节点:
- `mainland-controller-01`
- `mainland-worker-01`
- `overseas-control-01`
但 40 秒观察窗口前后完全一致:
- `progress_percent = 2.1`
- `completed = 21`
- `running = 14`
- `claimed = 34`
- `pending = 931`
### 2. mainland 逐条结果没有继续增长
中央查询结果:
- mainland `domain_*` 事件数仍为 `10`
- 最新 mainland `detect_result_ingest` 仍是:
- `id = 5382`
- `created_at = 2026-04-19 03:10:14`
说明:
- 首批同步成功过
- 但后续没有继续流入新结果
### 3. go-live 与 stack 口径已经比之前更完整
当前:
- `remote_access_ready = 3/3`
- `log_sync_state = full_capture`
- `go_live_status = attention`
这说明:
- 基础运维骨架已经起来
- attention 现在不能只归因于接管未完成
### 4. controller 现场日志已直接指向代理/外部依赖问题
`mainland-controller-01` 现场日志显示:
- `当前可用代理数: 0`
- `最近结果: 刷新成功,可用 0 个`
- 检测链包含:
- 注册
- 百度 site
- 360 site
- 站长之家
- 爱站
- 时光机
### 5. 页面上的“外部站点异常”与现场证据一致
从当前现场判断:
- 这不是页面误报
- 而是执行面确实卡在外部依赖/代理可用性上
## 下一轮唯一应该做什么
下一轮不要发散实现,只做 `J2-检测执行停滞收口批`
1. 继续只读确认:
- `/api/v1/detect/job/active`
- `/api/v1/runtime/sync-summary`
- `/api/v1/ops/activity-stream`
- `/api/v1/ops/nodes/{node_code}/scene-log`
2. 必要时补一轮:
- `domaincheck-worker` 运行日志取证
3. 只判断三件事:
- 是否仍然 `近窗吞吐 0`
- 是否仍然 `可用代理数 0`
- 是否仍然没有新 `domain_*` 事件
## 现在不要做什么
- 不做新页面
- 不做控制面增强
- 不做发布动作
- 不做 item 级最终回写
- 不把当前状态误判成“已稳定可签收”
## 一句话结论
当前项目已经不是“接不管、看不见、不同步”,而是“接管和同步都基本打通了,但检测执行卡在外部站点/代理可用性问题上,导致任务挂起且没有继续产出”。

View File

@@ -0,0 +1,117 @@
# HANDOFF 2026-04-19 03:24
## 本轮做了什么
本轮没有进入新实现,只做了执行面根因收紧:
1. 继续观察活跃检测任务是否前进
2. 继续观察 mainland `domain_*` 是否增长
3. 通过正式 `ops job` 远端采集:
- `mainland-controller-01`
- `mainland-worker-01`
`domaincheck-worker` 日志
4. 再盯一个 35 秒窗口,看 full capture 打开后,源日志时间是否继续前进
## 本轮结论
这轮已经能把问题说得更准:
- 不是“日志没回来”
- 不是“全量日志没开”
- 而是日志链路已经通了,但执行进程没有继续产生日志
当前第一主阻塞:
- `mainland-controller-01` 代理池可用数为 0
次级问题:
- `mainland-worker-01` 的时光机依赖异常会降级继续执行
## 关键证据
### 1. full capture 是开的,但源日志没继续前进
当前:
- `mainland-controller-01`
- `capture_at = 2026-04-19 03:21:59`
- 源日志时间仍停在 `Apr 19 01:00:23`
- `mainland-worker-01`
- `capture_at = 2026-04-19 03:22:01`
- 源日志时间仍停在 `Apr 19 02:19:56`
35 秒后再次复查:
- `capture_at` 没变化
- `source_msg` 也没变化
说明:
- 日志回传本身不是主问题
- 执行进程这段时间没有继续产生日志
### 2. controller 代理源能拉到数据,但所有代理都验不过
`mainland-controller-01``domaincheck-worker` 日志显示:
- 6 个代理源都能拉到原始代理
- 抽样验证 24 个代理后:
- `代理池刷新完成,共 0 个可用代理`
- 失败集中在:
- `ProxyError@https://m.baidu.com`
- `Unable to connect to proxy`
- `ConnectTimeoutError`
说明:
- 不是代理接口挂了
- 是代理名单本身不可用
### 3. worker 还能跑,但时光机依赖异常会降级
`mainland-worker-01``domaincheck-worker` 日志显示:
- `时光机检测 外部依赖异常,步骤降级继续执行`
- 同时仍可见:
- `域名检测完成`
- 收到新的控制消息时:
- `收到启动检测指令,但检测任务已在运行,忽略重复启动`
说明:
- worker 不是完全不可用
- 时光机异常存在,但不是最核心阻塞
### 4. 活跃任务仍然没有前进
- `progress_percent = 2.1`
- `completed = 21`
- `running = 14`
- `claimed = 34`
- `pending = 931`
并且 mainland `domain_*` 仍固定在 `10`
## 下一轮唯一应该做什么
继续只做 `J2-检测执行停滞收口批`
1. 不扩功能
2. 不改页面
3. 只围绕 controller 代理池问题取证和恢复验证
唯一要确认的是:
- controller 代理池是否仍然 `可用 0`
- 一旦代理恢复,`domain_*` 是否会继续增长
## 现在不要做什么
- 不把问题继续泛化成“外部站点都异常”
- 不把问题误判为“日志回传没开”
- 不做新页面、新模块、发布动作
## 一句话结论
当前项目不是“接管失败”也不是“日志没回来”而是“controller 侧拉到了代理名单,但代理全部校验失败,导致检测执行没有继续产生新结果”。

View File

@@ -0,0 +1,122 @@
# HANDOFF 2026-04-19 03:32
## 本轮做了什么
这轮没有扩功能,没有进新页面,也没有碰发布动作。
只做了两件事:
1. 把检测执行停滞的判断继续收紧
2. 对 worker 控制消息链补上最小代码修复
## 当前最新判断
当前不是接管问题,也不是日志回传问题。
当前真实状态是:
- `remote_access_ready = 3/3`
- `log_sync_state = full_capture`
- 大陆首批结果同步已经成功过
- 但检测任务没有持续前进
这个停滞目前有两层原因:
### 第一层:已确认的现场阻塞
- `mainland-controller-01` 代理池刷新后 `0 available`
- 代理源可以拉到原始代理
- 但抽样校验全部失败
这会直接影响 controller 侧吞吐。
### 第二层:刚补好的代码风险
之前存在一个运行态风险:
- 控制面发 `start_detection`
- Redis `publish` 成功
- 但 worker 如果漏收 pubsub 消息
- pending 指令可能不会在运行态被再次消费
这会造成:
- 页面像是发起成功了
- 但 worker 不一定真的继续推进
现在这处代码缺口已经补上,但还没有完成线上部署验证。
## 本轮代码修复
### 1. `worker_control_service`
文件:
- `domain-api/app/services/worker_control_service.py`
修复:
- 每条 worker 控制消息补 `request_id`
- Redis `publish` 和 pending fallback 复用同一条消息体
### 2. `detect_worker`
文件:
- `domainCheck/detect_worker.py`
修复:
- 运行态心跳里周期性补偿消费 pending 控制消息
- 真正收到控制消息后,按 `request_id` 清理 pending
### 3. 新增测试
文件:
- `domain-api/tests/test_worker_control_service.py`
验证目标:
- 确保 `send_worker_command(...)` 会生成并持久化 `request_id`
## 本地验证结果
已通过:
```bash
PYTHONPATH=/www/wwwroot/getDomain/domain-api /opt/domaincheck/domainCheck/.venv/bin/python -m unittest domain-api/tests/test_worker_control_service.py
python -m py_compile domainCheck/detect_worker.py domain-api/app/services/worker_control_service.py
```
## 下一轮唯一该做什么
下一轮不要发散,只做最小部署验证:
1. 大陆节点拉最新代码
2. 重启 `domaincheck-worker`
3. 复查:
- `/api/v1/detect/job/active`
- `/api/v1/runtime/sync-summary`
- controller / worker `scene-log`
- 必要时再采集 `domaincheck-worker` 日志
4. 只判断两件事:
- 修复上线后,检测任务是否恢复推进
- 如果仍不推进,是否只剩 controller 代理池 `0 available` 这个现场阻塞
## 现在不要做什么
- 不做新页面
- 不做新模块
- 不做控制面增强
- 不做发布动作
- 不把问题再泛化成“日志没回来”或“接管没完成”
## 一句话结论
当前最准确的状态是:
- 接管和同步基本已经闭合
- 检测执行停滞仍然存在
- worker 控制消息补偿链已补代码
- 下一步只剩“拉代码重启 worker 后看任务是否恢复推进”

View File

@@ -0,0 +1,142 @@
# HANDOFF 2026-04-19 03:41
## 本轮做了什么
这轮没有扩功能,只沿着检测执行停滞的最小路径继续推进,完成了:
1. 将提交 `c33f4f1` 部署到:
- `mainland-worker-01`
- `mainland-controller-01`
2. 重启两台大陆节点的 `domaincheck-worker`
3. 验证 worker 控制消息补偿链是否在线上生效
4. 排查 controller 为什么没有像 worker 一样顺滑接入控制链
5. 修正 controller 运行环境中的 Redis 密码漂移
6. 再次下发 `detect/start`,确认 controller 真正收到并执行新启动指令
7. 再观察中央进度、recent events、sync-summary 是否继续前进
## 本轮关键结果
### 1. worker 控制消息补偿链已经线上生效
`mainland-worker-01` 明确出现:
- `发现待执行 Worker 控制指令`
- `已接受检测启动指令`
- `开始执行远程检测任务`
这说明:
- 上一轮代码修复不是只在本地成立
- pending 控制消息补偿消费链已经在线上闭合
### 2. controller 原先确实存在运行环境漂移
`mainland-controller-01``/etc/default/domaincheck-worker` 原始状态:
- `REDIS_HOST=127.0.0.1`
- `REDIS_PORT=6379`
- `REDIS_PASSWORD=`
对应日志:
- `Authentication required`
- `maximum recursion depth exceeded while calling a Python object`
这说明:
- controller 不是没重启
- 也不是代码没生效
- 而是本机 Redis 开了鉴权,但 worker 环境文件没带密码
### 3. controller 已完成最小修正并重新接上控制链
本轮已把 controller 的 `REDIS_PASSWORD` 补为:
- `Qazwe123..`
修正后再次重启,日志变为:
- `Redis 连接成功: 127.0.0.1:6379`
- `已接受检测启动指令`
- `开始执行远程检测任务`
之后再次触发 `/api/v1/detect/start`controller 又出现:
- `发现待执行 Worker 控制指令`
- `收到启动检测指令,但检测任务已在运行,忽略重复启动`
这说明:
- controller 的控制链也已经恢复
- 现在不再是 Redis 断链问题
### 4. 当前唯一剩余阻塞已经进一步收紧
controller 当前最新现场日志反复出现:
- `代理已启用,但当前无可用代理`
这意味着当前唯一剩余主阻塞已经收紧为:
- `mainland-controller-01` 代理池没有可用代理
## 中央侧当前表现
正向信号:
- `remote_access_ready = 3/3`
- `log_sync_state = full_capture`
- `runtime/sync-summary` 最新记录继续增长到 `5491`
- recent events 已刷新到更晚时间
- `mainland-worker-01` 最新 domain_started 已推进到 `2026-04-19 16:37:00`
仍未恢复的信号:
- `items_completed = 21`
- `items_claimed = 34`
- `items_running = 14`
- `items_pending = 931`
- 短观察窗口内没有继续上涨
这说明:
- 控制链和同步链已经恢复到更健康状态
- 但执行吞吐还没有恢复成“持续出结果”
## 当前结论
当前最准确的判断是:
- 接管问题:基本已闭合
- 日志回传问题:已闭合
- worker 控制消息漏收问题:已闭合
- controller Redis 环境漂移:已闭合
- 当前唯一剩余阻塞:`mainland-controller-01` 代理池无可用代理
## 下一轮唯一应该做什么
下一轮不要发散,只做 controller 代理收口:
1. 继续观察 controller `domaincheck-worker` 日志
2. 重点看是否从:
- `代理已启用,但当前无可用代理`
转成:
- 至少有 `1+` 可用代理
3. 继续复查:
- `/api/v1/detect/job/active`
- `/api/v1/runtime/sync-summary`
- `/api/v1/ops/nodes`
4. 只判断一件事:
- controller 代理恢复后,`items_completed` 是否继续增长
## 现在不要做什么
- 不扩页面
- 不做新模块
- 不做控制面增强
- 不误判成“接管还没好”
- 不继续围绕 worker 控制消息链做重复修复
## 一句话结论
这轮已经把系统从“控制链也有缺口”推进到了“控制链已恢复、只剩 controller 代理池无可用代理”。

View File

@@ -0,0 +1,66 @@
# HANDOFF 2026-04-19 04:26 CST
## 本轮完成
- 已修复 `runtime/status` 兼容层,恢复旧字段:
- `api_online`
- `worker_online`
- `cluster_summary`
- `thread_count`
- 已重启中央 `domaincheck-api`
- 已重新构建 `domain-web` 前端静态包
- 已确认大陆双节点日志回传同时进入中央:
- `mainland-controller-01`
- `mainland-worker-01`
- 已确认大陆两台线程配置真实生效:
- `mainland-controller-01 -> 100`
- `mainland-worker-01 -> 50`
## 当前真实状态
- `/api/v1/runtime/status`
- `api_online = true`
- `worker_online = true`
- `cluster_summary.online_worker_nodes = 3`
- `/api/v1/detect/status`
- `progress.pending = 163815`
- `progress.completed = 51`
- `progress.running = 10`
- `remote_log_line_count = 240`
- `remote_log_node_count = 2`
- 近 5 分钟中央 `detect_debug_events`
- `mainland-controller-01 -> worker_log`
- `mainland-worker-01 -> worker_log`
## 当前结论
- “API 离线 / 本机 Worker 离线 / 有效执行节点 0” 已不是后端真实状态
- “全量日志没回来” 已不是后端真实状态
- “100/50 并发没有下发” 也不是后端真实状态
- 当前剩余主问题已经收紧为:
- 检测实际吞吐仍偏低
- 代理可用性与任务分发节奏仍在限制体感并发
## 下一轮唯一任务
只做:`J2-检测执行吞吐收口`
顺序:
1. 强刷浏览器,确认新前端包已经生效
2. 复查 Detect 页是否恢复:
- API 在线
- 本机 Worker 在线
- 有效执行节点 > 0
- 日志窗口出现双节点日志
3. 若显示已恢复,再继续只排查:
- 为什么实际执行吞吐仍低于 `100/50`
- 重点看代理可用性、任务领取节奏、线程实际活跃数
## 现在不要做
- 不扩新页面
- 不扩控制面功能
- 不新增专题文档
- 不进入发布动作
- 不切新大方向

View File

@@ -0,0 +1,104 @@
# HANDOFF 2026-04-19 13:34 CST
## 本轮完成
- 已修复 controller `sync-agent pull_tasks` 只导 `domains`、不导本地执行队列的问题
- 已让 controller 持续创建本地镜像任务:
- `sync-overseas-7380`
- `sync-overseas-7383`
- `sync-overseas-7392`
- 后续批次持续增加
- 已重启两台大陆 `domaincheck-worker`
- 已确认两台大陆节点都进入真实任务队列:
- `mainland-controller-01 -> 从任务队列获取到 800 个需要检测的域名`
- `mainland-worker-01 -> 从任务队列获取到 400 个需要检测的域名`
- 已修复 controller `runtime/detect_runs.json` 属主错误:
- `root:root -> www:www`
- 已确认 `runtime_projection` 最新同步恢复成功:
- `sync_state = success`
- `runtime_projection -> 投影推送成功`
## 当前真实状态
当前 `/api/v1/ops/nodes` 已显示:
- `remote_access_ready = 3`
- `participating = 3`
- `dispatch_active = 1`
大陆两台当前状态:
- `mainland-controller-01`
- `agent_state = online_busy`
- `detect_runtime.max_threads = 100`
- `processed_recent = 115`
- `processed_per_minute = 7.67`
- `is_current_participant = true`
- `mainland-worker-01`
- `agent_state = online_busy`
- `detect_runtime.max_threads = 50`
- `processed_recent = 632`
- `processed_per_minute = 42.13`
- `is_current_participant = true`
## 当前结论
- 大陆两台不是“在线但没干活”
- 而是已经进入真实镜像队列执行
- `100/50` 并发也不是停留在配置层,而是已经开始真实消费任务
- 后台运行态同步链已经恢复
现在剩余问题已经收敛到:
- Detect 页面主计数 / 日志窗口是否完全跟上新的运行态
- 恢复后的吞吐是否能持续稳定
## 一个关键口径说明
当前大陆执行是“镜像队列”模式:
- 海外待检测批次先被 controller 拉回大陆本地
- 在大陆本地形成 `sync-overseas-*``detect_jobs/detect_job_items`
- 再由大陆 worker 真正执行
- 运行态和结果再同步回海外
所以现在不要再只盯中央原生 `detect_job_items.claimed/running` 判断大陆有没有参与。
应该优先看:
- `/api/v1/ops/nodes`
- `processed_recent`
- `processed_per_minute`
- `detect_runtime.active_threads/max_threads`
## 下一轮唯一任务
只做:`J2-页面口径与吞吐稳定性收口`
顺序:
1. 继续观察 Detect 页面
2. 确认日志窗口是否已经持续刷新
3. 确认主计数是否开始跟随最新运行态
4. 继续观察 1 到 2 个同步周期内:
- `mainland-controller-01 processed_recent`
- `mainland-worker-01 processed_recent`
- `processed_per_minute`
5. 若页面仍不跟,优先修页面读取口径,不扩功能
## 现在不要做
- 不扩新页面
- 不扩控制面功能
- 不新增模块
- 不进入发布动作
- 不切新方向
## 推荐模型
- 当前最合适:`GPT-5.4 + high`
原因:
- 现在主要是收口、验证、局部修复
- 需要稳定推理,但不需要切到超高

View File

@@ -0,0 +1,109 @@
# HANDOFF 2026-04-19 13:48 CST
## 本轮完成
- 已定位并修复 `domainCheck/detect_worker.py` 的上下文绑定缺口:
- `sync-pull` 控制消息只有
- `target_job_id`
- `target_job_code`
- 旧逻辑只读取
- `job_id`
- `job_code`
- 结果是 `mainland-worker-01` 明明已经在跑,但 `current_job_id` 为空,`worker_log` 被整段短路
- 已把补丁同步到:
- `mainland-controller-01:/opt/domaincheck/domainCheck/detect_worker.py`
- `mainland-worker-01:/opt/domaincheck/domainCheck/detect_worker.py`
- 已在两台大陆机完成:
- `python -m py_compile /opt/domaincheck/domainCheck/detect_worker.py`
- `systemctl restart domaincheck-worker`
## 当前硬证据
### 1. mainland worker 日志回传已恢复
当前 `/api/v1/runtime/debug-events` 已出现:
- `mainland-worker-01 -> 开始执行检测任务,来源: redis-control`
- `mainland-worker-01 -> 开始执行域名检测任务,正在加载配置`
- `mainland-worker-01 -> 开始检测,正在刷新代理池`
- `mainland-worker-01 -> 代理池刷新完成,共 7 个可用代理,来源链接 6 个,原始 265 个,验证 150 个`
- `mainland-worker-01 -> 从任务队列获取到 400 个需要检测的域名`
- `mainland-worker-01 -> 开始创建线程,当前批次域名数: 400最大线程数: 50`
- `mainland-worker-01 -> 当前实际线程数量: 1/50`
- `mainland-worker-01 -> 当前实际线程数量: 2/50`
- `mainland-worker-01 -> 当前实际线程数量: 3/50`
### 2. Detect 页面远端日志已经恢复双节点
当前 `/api/v1/detect/status` 已显示:
- `remote_log_node_count = 2`
- `remote_log_nodes = ["mainland-controller-01", "mainland-worker-01"]`
最近日志样本:
- `mainland-worker-01 -> 从任务队列获取到 400 个需要检测的域名`
- `mainland-worker-01 -> 开始创建线程,当前批次域名数: 400最大线程数: 50`
- `mainland-worker-01 -> 当前实际线程数量: 1/50`
- `mainland-worker-01 -> 当前实际线程数量: 2/50`
- `mainland-worker-01 -> 当前实际线程数量: 3/50`
- `mainland-controller-01 -> 当前实际线程数量: 1/100 ... 3/100`
### 3. 三台节点仍保持参与态
当前 `/api/v1/ops/nodes` 摘要:
- `online = 3`
- `agent_ready = 3`
- `remote_access_ready = 3`
- `participating = 3`
- `dispatch_active = 1`
## 当前判断
已经闭合:
- 大陆节点真实执行
- mainland worker 日志回传
- Detect 页面远端日志窗口只显示 controller 的问题
仍待收口:
- Detect 页面主计数:
- `pending = 163678`
- `completed = 195`
- `running = 3`
- 当前这些主计数还没有和这轮大陆执行立即同步推进
因此当前剩余唯一主问题已经缩成:
- `detect_result_projection / 结果统计回推` 是否还存在延迟或聚合口径缺口
## 下一轮唯一任务
只做:`J2-结果计数收口批`
顺序:
1. 复查 `detect_result_projection` 最新推送是否持续成功
2. 复查 mainland 共享库里 `sync-overseas-*` 任务的完成/失败数量是否增长
3. 复查 overseas `detect/status.progress` 是否跟着推进
4. 若日志继续推进但主计数仍不动,只修结果统计回推口径,不扩功能
## 现在不要做
- 不扩新页面
- 不扩控制面功能
- 不新增模块
- 不切新方向
- 不直接进入发布动作
## 推荐模型
- 当前继续用:`GPT-5.4 + high`
原因:
- 现在是收口型问题
- 需要稳定排查与小范围补丁
- 不需要切超高推理

View File

@@ -0,0 +1,65 @@
# HANDOFF 2026-04-19 14:16 CST
## 本轮完成
- 已修复 `detect_worker.py` 中“代理不足反向限制并发”的热路径:
- 代理池不足时改为后台补货
- 不再因为 `current_pool_size < thread_count/2` 而同步刷新、拖慢线程拉起
- 已对线程创建阶段的运行态 / worker_log 做节流:
- 不再每起一个线程就同步打一轮重日志
- 避免远端日志回传本身把并发拉低
- 已把上述修复部署到:
- overseas 当前 live 运行目录 `/opt/domaincheck/domainCheck/detect_worker.py`
- repo 目录 `/www/wwwroot/getDomain/domainCheck/detect_worker.py`
- `mainland-controller-01`
- `mainland-worker-01`
- 已补上“真实活跃检测线程计数”逻辑到代码文件中
## 当前结果
- `mainland-controller-01`
- 海外后台当前已能看到:
- `active_threads ~= 99~100`
- `max_threads = 100`
- 结论:
- controller 的 `100` 并发已经真实跑起来
- `mainland-worker-01`
- 已重新接到新批次:
- `source_record_id = 7679`
- `target_job_code = sync-overseas-7679`
- 最新日志已出现:
- `开始执行域名检测任务`
- `开始检测,刷新代理池`
- `代理池刷新完成,共 23 个可用代理`
- `开始创建线程,当前批次域名数: 400最大线程数: 50`
- 本机进程线程量:
- `152`
- 结论:
- worker 已重新进入真实执行
- 但 overseas 后台对 `mainland-worker-01.active_threads/current_load` 的显示仍偏低
## 当前剩余问题
- 不是 controller 并发限制问题
- 当前唯一剩余的运行面收口点是:
- `mainland-worker-01` 的运行态上报 / 后台显示口径仍未完全对齐
- 同时仍需继续观察:
- Detect 页面主计数 `pending/completed/running`
- 结果统计回推是否继续推进
## 下一轮建议
只继续做这两件事:
-`mainland-worker-01` 的运行态采集链:
- 为什么本机已进入新批次执行,但海外后台仍显示 `active_threads = 2`
- 继续核对 Detect 主计数与结果回推:
- 判断是统计延迟、投影延迟,还是任务结果尚未进入中央口径
不要做:
- 新页面
- 新模块
- 控制面增强
- 发布动作
- 新专题文档

View File

@@ -0,0 +1,52 @@
# HANDOFF_20260419_1421
更新时间2026-04-19 14:21 CST
## 本轮完成
- 已完成检测页前端布局收口并上线验证:
- `任务日志控制台` 已上移到事件列表前
- `检测事件流` 已改成独立滚动区域
- 事件表已限制最大高度,避免页面被长列表持续撑长
- 已在真实线上静态目录重新构建:
- `/www/wwwroot/getDomain/domain-web/dist`
- 已验证线上 Nginx 实际指向该目录:
- `/www/server/panel/vhost/nginx/domaincheck_3201.conf`
- `/www/server/panel/vhost/nginx/domaincheck_152.53.37.118.conf`
- 已验证本机线上端口可返回新页面:
- `curl -I http://127.0.0.1:3201/ -> 200`
- `index.html` 最后修改时间已更新到本轮
- 新资源:
- `/assets/DetectView-B9S1WMRT.js`
- `/assets/DetectView-BFxMNRNR.css`
## 当前判断
- 这轮前端布局任务已经闭环
- 如果浏览器仍显示旧布局,优先判断为缓存未刷新
- 当前更值得继续追的不是页面结构,而是:
- `mainland-worker-01` 运行态上报口径
- Detect 主计数推进
- 并发真实吞吐继续拉升
## 下一步建议
下一轮继续只围绕检测执行收口:
- 复核 `mainland-worker-01` 为什么本机线程已拉起,但后台 `active_threads/current_load` 仍偏低
- 继续比对:
- `/api/v1/detect/status`
- `/api/v1/runtime/debug-events`
- `/api/v1/ops/nodes`
- 继续验证 Detect 页面主计数是否跟随真实执行推进
## 本轮关键命令证据
```bash
cd /opt/domaincheck/domain-web && npm run build
curl -I http://127.0.0.1:3201/
curl http://127.0.0.1:3201/
rg -n "event-stream-panel|任务日志控制台|检测事件流" \
/www/wwwroot/getDomain/domain-web/dist/assets/DetectView-BFxMNRNR.css \
/www/wwwroot/getDomain/domain-web/dist/assets/DetectView-B9S1WMRT.js
```

View File

@@ -0,0 +1,54 @@
# HANDOFF_20260419_1429
更新时间2026-04-19 14:29 CST
## 本轮完成
- 已修复代理链“配置已下发但长期停留未刷新”的问题
- `domaincheck-worker` 现在会在以下时机主动刷新代理池:
- worker 启动后
- `proxy_config`
- `thread_count`
- `node_thread_counts`
- `runtime_settings`
- 以上配置更新后
- 已重启:
- `domaincheck-worker`
- `domaincheck-api`
- 已完成一次真实代理池刷新并拿到明确结果:
- 原始代理数:`202`
- 抽样验证数:`24`
- 可用代理数:`0`
## 当前状态
- 当前后台不再显示误导性的“未刷新”
- 当前真实状态为:
- `proxy_runtime_label = 降级直连`
- `proxy_runtime_reason = proxy_validation_zero`
- `proxy_runtime_detail = 代理源最近返回了 202 个代理,已验证 24 个,但当前 0 个可用;系统已自动降级为直连继续执行;最近状态:刷新成功,可用 0 个`
## 关键判断
- 这批代理当前的主要问题不是“系统没去用”
- 而是:
- 代理源会返回很多 IP
- 但 worker 实测校验时全部失败
- 失败以 `ProxyError / ConnectTimeout` 为主
## 下一步建议
- 优先不要再纠结“为什么页面写未刷新”
- 这一层已经修好
- 下一轮如果继续优化代理,应只做以下两种之一:
- 更换/补充代理供应组,重新验证可用率
- 调整代理校验策略,但要接受更高的脏代理混入风险
## 现场证据
```text
主动触发代理池刷新: worker_startup
代理池链接拉取成功 ... 原始代理数: 50 / 50 / 0 / 50 / 2 / 50
代理池验证已启用抽样模式,本次抽样 24 个代理进行可用性验证
代理池刷新完成,共 0 个可用代理,来源链接 6 个
```

View File

@@ -0,0 +1,42 @@
# HANDOFF_20260419_1450
更新时间2026-04-19 14:50 CST
## 本轮完成
- 已继续优化代理链,不只停留在“看见 0 可用”
- 已新增两项优化:
- 扩展严格验证目标:
- `baidu`
- `m.baidu`
- `qq`
- `360`
- 当严格验证 `0` 命中时,启用:
- `宽松入池 + 快速隔离`
## 当前结果
- 当前最新代理刷新结果:
- `proxy_last_refresh_total_items = 270`
- `proxy_last_validated_count = 24`
- `proxy_last_available_count = 2`
- `proxy_last_refresh_status = 宽松入池 2 个(严格校验 0 命中)`
- 后台当前已显示:
- `available_proxy_count = 2`
- `proxy_runtime_detail = 代理池当前可用 2 个代理,配置来源 6 个;最近状态:宽松入池 2 个(严格校验 0 命中)`
## 关键判断
- 严格校验下,这批代理整体质量依然偏差
- 但现在已经不再是完全 `0` 可用
- 系统已成功放出少量试跑代理,可以继续观察:
- 是否带动检测吞吐
- 是否很快被失败隔离重新打回 `0`
## 下一步
- 优先观察这 `2` 个试跑代理是否真的参与检测执行
- 如果能参与并带来吞吐,再继续逐步放宽
- 如果很快再次掉回 `0`,下一轮就应转到:
- 补代理供应组
- 或按地区/分组拆分代理质量统计

View File

@@ -0,0 +1,64 @@
# HANDOFF 2026-04-19 14:54 CST
## 本轮目标
把代理链从“预验证优先”切到用户指定的最小高效路径:
- 只去掉过期 / 非法代理
- 不再单独做可用性预验证
- 直接投入真实检测
- 失败即淘汰并触发补刷
## 本轮已完成
- 已修改 [detect_worker.py](/www/wwwroot/getDomain/domainCheck/detect_worker.py)
- `refresh_proxy_pool()`
- 移除预验证入池逻辑
- 仅做过期 / 非法 / 去重过滤
- 直接把代理源返回结果入池
- `remove_proxy()`
- 代理失败后不再留在当前池尾部
- 直接从当前池移除
- 保留失败标记并在低水位时触发补刷
- 已重启 `domaincheck-worker`
- 已确认 worker 新日志进入运行态
## 最新运行证据
- worker 最新日志:
- `代理池刷新完成,共 270 个入池代理,来源链接 6 个,原始 270 个,去过期 0 个,非法 0 个`
- API 最新状态:
- `available_proxy_count = 270`
- `proxy_last_refresh_status = 直入池 270 个(跳过预验证)`
- `proxy_last_validated_count = 0`
- `proxy_runtime_reason = healthy`
## 当前判断
- 这轮目标已经完成
- 代理链现在已经符合“直接跑任务,失败就丢弃代理并换新”的要求
- 下一步不该再回头做单独代理预验证
## 下一步主任务
唯一主任务:
- 继续观察真实检测吞吐是否随直入池策略抬升
- 重点看:
- `/api/v1/detect/status`
- `/api/v1/ops/nodes`
- 检测页主计数 `pending/completed/running`
- 失败代理淘汰后是否能持续自动补池
## 若下一轮继续
优先处理:
- “并发已下发但主计数不明显推进”的统计 / 调度口径问题
不要处理:
- 不要重新加回重预验证逻辑
- 不要扩展新页面
- 不要扩展控制面新模块
- 不要发散到发布链或新专题文档

View File

@@ -0,0 +1,107 @@
# HANDOFF_20260419_2053
更新时间2026-04-19 20:53 CST
## 本轮完成
- 修复发布打包遗漏:
- 最新发布包现在已包含 `domainCheck/`
- 最新正式签收包:
- `domaincheck_release_20260419_205437`
- 修复发布任务观测性:
- `domain-api/app/services/ops_release_executor_core.py`
- 发布目录不可写时显式失败
- 增加 `ExecStart``current` 软链对齐观测
- `domain-api/app/node_agent.py`
- 增加 job 级兜底异常回写,避免任务假性卡死
- 将卡死的 worker 发布任务纠正为真实失败:
- `release_id = 6`
- `rollout_id = 5`
- `job_id = 204`
- 当前已从假 `running` 回正为 `failed`
- 本次失败对应的 Release 版本:
- `domaincheck_release_20260419_203933`
## 今晚新增关键结论
### 1. worker 发布失败的真实原因已明确
- `mainland-worker-01`
- node-agent 日志:
- `2026-04-19 20:40:15 [node-agent] loop error: [Errno 13] Permission denied: '/opt/domaincheck/downloads'`
- 对应发布任务:
- `job 204 = failed`
- `rollout 5 = failed`
- 当前失败原因已经正式回写:
- `install_root not writable: /opt/domaincheck/downloads`
### 2. mainland 两台节点都不符合当前 ReleaseHub 发布模型
- `mainland-worker-01`
- `domaincheck-worker` 当前启动路径:
- `/opt/domaincheck/domainCheck/detect_worker.py`
- `mainland-controller-01`
- `domaincheck-worker` 当前启动路径:
- `/opt/domaincheck/domainCheck/detect_worker.py`
这意味着:
- 当前线上服务不是跑在
- `/opt/domaincheck/current/domainCheck/...`
- 所以即使发布成功切了 `current` 软链
- 也不会自动让现有 systemd 服务切到新版本
### 3. worker 当前不是新版本高吞吐样本
- `mainland-worker-01`
- `Active since = 2026-04-19 18:18:50 CST`
- `Main PID = 635924`
- `CPU = 18.994s`
- 最近日志仍停留在旧代码行号:
- `_run_detect_register:2465`
- `detect_domain:2947`
- `start_redis_subscription:3590`
说明:
- worker 仍是旧进程
- 当前不能把它当成“已切新包并真实参与高吞吐”的有效证据
## 结论
当前唯一主阻塞不是前端、不是统计口径、也不是单纯并发参数。
当前唯一主阻塞是:
- mainland 节点 `deploy.release` 目录权限不满足
- mainland 节点 `domaincheck-worker` 的 systemd `ExecStart` 与 ReleaseHub 的 `current` 发布模型不一致
在这两个问题修正前:
- 不建议继续对 mainland 节点做正式 rollout
- 不建议继续把 worker 统计口径偏差当成纯展示层问题
## 下一步唯一建议
1. 先修 mainland 节点发布基座
- 让 node-agent 对 `/opt/domaincheck/downloads``/opt/domaincheck/releases` 有写权限
- 或明确改成一个 node-agent 真正可写的发布根目录
2. 再统一 `domaincheck-worker.service`
-`ExecStart` 指向 `/opt/domaincheck/current/domainCheck/detect_worker.py`
- 不再直指 `/opt/domaincheck/domainCheck/detect_worker.py`
3. 完成后重新发起:
- worker rollout
- 验证 PID 切换
- 验证代码行号切换到当前版本
- 再看吞吐和 CPU 利用率
## 本轮改动文件
- `package_domain_release.sh`
- `verify_domain_release.sh`
- `package_domain_release.ps1`
- `verify_domain_release.ps1`
- `domain-api/app/services/ops_release_executor_core.py`
- `domain-api/app/node_agent.py`
- `docs/ops_center_runtime/TASK_BOARD.md`
- `docs/ops_center_runtime/IMPLEMENTATION_STATUS.md`

View File

@@ -0,0 +1,102 @@
# HANDOFF_20260419_2117
更新时间2026-04-19 21:17 CST
## 本轮结论
`mainland-worker-01` 的最新正式 rollout 已完成根因收口:
- `release_id = 7`
- `rollout_id = 6`
- `job_id = 211`
执行结果:
- 发布包下载成功
- `/opt/domaincheck/downloads/domaincheck_release_20260419_205437.tar.gz`
- release 解压成功
- `/opt/domaincheck/releases/domaincheck_release_20260419_205437`
- `current` 软链切换成功
- `/opt/domaincheck/current -> /opt/domaincheck/releases/domaincheck_release_20260419_205437`
- 最终失败在:
- `systemctl restart domaincheck-worker`
控制面失败结果原文:
- `restart failed: domaincheck-worker`
- `Failed to restart domaincheck-worker.service: Interactive authentication required.`
## 真实根因
不是发布包问题,也不是目录权限问题了。
当前根因是:
- `domaincheck-node-agent` 运行身份仍是 `www`
- 它具备下载、解压、切换 `current` 的权限
- 但不具备执行 systemd 服务重启的权限
所以当前所有以下动作在 mainland 机器上都会有同类风险:
- `deploy.release`
- `service.restart`
- 任何依赖 node-agent 直接操作 systemd 的动作
## 本轮已做代码修正
已修改:
- `domain-api/deploy/systemd/domain-node-agent.service`
- `User=root`
- `Group=root`
- `domain-api/deploy/multi-region/fix_mainland_release_base.sh`
- 安装 node-agent drop-in 时补齐:
- `User=root`
- `Group=root`
已验证:
- `bash -n domain-api/deploy/multi-region/fix_mainland_release_base.sh`
## 现场下一步
下一步不要再重复发起新的 rollout先把 `mainland-worker-01` 的 node-agent 切到 root。
建议现场执行:
```bash
mkdir -p /etc/systemd/system/domaincheck-node-agent.service.d
cat >/etc/systemd/system/domaincheck-node-agent.service.d/runtime-user.conf <<'EOF'
[Service]
User=root
Group=root
EOF
systemctl daemon-reload
systemctl restart domaincheck-node-agent
systemctl status domaincheck-node-agent --no-pager -l
```
完成后应立即复查:
```bash
systemctl show domaincheck-node-agent -p User -p Group
journalctl -u domaincheck-node-agent -n 80 --no-pager -l
```
预期结果:
- `domaincheck-node-agent``root` 身份运行
- 心跳恢复,`mainland-worker-01` 不再是 `stale`
- 后续再发起 `deploy.release` 时,能够闭环到 `systemctl restart domaincheck-worker`
## 当前判断
当前主阻塞只剩一个:
- mainland node-agent 权限模型未切到 root
这个问题修完后,再重新发起 worker rollout才有资格继续看
- `domaincheck-worker` 是否切到新 PID
- health check 是否通过
- rollout 6 之后的 acceptance 是否可继续

View File

@@ -0,0 +1,95 @@
# HANDOFF_20260419_2125
更新时间2026-04-19 21:25 CST
## 本轮结果
`mainland-worker-01` 的 release rollout 已正式成功收口。
关键信息:
- `release_id = 7`
- `rollout_id = 7`
- `job_id = 214`
最终状态:
- `job 214 = success`
- `rollout 7 = completed`
- `mainland-worker-01.agent_state = online_busy`
## 成功证据
控制面 `job events` 已记录:
- `event_type = agent_completed`
- `summary_text = release deployed`
结果载荷中已确认:
- `release_version = domaincheck_release_20260419_205437`
- `restart_results`
- `domaincheck-worker.returncode = 0`
- `health_check.ok = true`
- `services_checked = ["domaincheck-worker"]`
- `execstart_alignment.mismatched_services = []`
说明这次已经完整走通:
1. 下载发布包
2. 解压 release
3. 切换 `/opt/domaincheck/current`
4. 重启 `domaincheck-worker`
5. 健康检查通过
## 为什么这次成功
不是发布逻辑变化了,而是现网权限问题被修掉了。
上一轮失败根因:
- `domaincheck-node-agent``www` 身份运行
- 无法执行 `systemctl restart domaincheck-worker`
- systemd 返回:
- `Interactive authentication required`
本轮修复:
- `mainland-worker-01`
- `domaincheck-node-agent` 已切为:
- `User=root`
- `Group=root`
## 当前剩余项
唯一建议立即同步的预防动作:
-`mainland-controller-01` 上,也把 `domaincheck-node-agent` 切成 `root`
原因:
- worker 已经验证这就是 release 闭环最后一层权限门槛
- controller 如果后续参与自身发布 / restart同样会遇到同类 systemd 权限问题
建议执行:
```bash
mkdir -p /etc/systemd/system/domaincheck-node-agent.service.d
cat >/etc/systemd/system/domaincheck-node-agent.service.d/runtime-user.conf <<'EOF'
[Service]
User=root
Group=root
EOF
systemctl daemon-reload
systemctl restart domaincheck-node-agent
systemctl show domaincheck-node-agent -p User -p Group
```
## 当前判断
关于 mainland worker 的发布链,已经不再是阻塞项。
现在可以进入下一步:
- 再决定是否对 `mainland-controller-01` 做同样 root 切换
- 然后继续 controller acceptance / rollout 收口

View File

@@ -0,0 +1,563 @@
# HANDOFF_20260420_1920
更新时间2026-04-20 19:20 CST
## 本轮结论
这轮最重要的收口已经完成:
- 已确认当前工作机 `/www/wwwroot/getDomain` 所在主机是海外测试控制面,不是国内 `mainland-controller-01`
- 已把“假冒 mainland-controller-01”的本机配置纠正为 `overseas-control-01`
- 已把真正的 `mainland-controller-01` 重新接回控制面,并完成一次成功的远端发布
- 已修正 `mainland-controller-01` 的 node-agent 身份上报问题
- 现在控制面里看到的 `mainland-controller-01` 已经是真实主机:
- `hostname = mainland-controller-01`
- `ip = 121.204.244.188`
一句话说当前状态:
“主线已经从‘节点身份混乱’推进到‘真 controller 已经对正并重新进场’,下一步应只盯 controller 真机吞吐和 worker 恢复,不要再回展示层。”
## 当前环境认知
### 1. 当前 Codex 所在机器不是大陆 controller
本地执行结果:
- `hostname = v2202604268673447256`
- `nproc = 12`
这台机器是海外控制面测试机,不是用户说的 112 核 controller。
真正的国内 controller 是:
- `node_code = mainland-controller-01`
- `ssh_host = 121.204.244.188`
真正的国内 worker 是:
- `node_code = mainland-worker-01`
- `ssh_host = 121.204.244.248`
### 2. 本机服务身份已经纠正
为避免海外测试机继续伪装成 mainland controller已经改过这些环境文件
- `/etc/default/domaincheck-worker`
- `/etc/default/domaincheck-node-agent`
- `/etc/default/domaincheck-api`
修正后的核心值:
- `NODE_CODE=overseas-control-01`
- `NODE_REGION=overseas`
- `SYNC_PUSH_ENABLED=false`
并且已经执行过:
- 停止本机 `domaincheck-worker`
- 停止本机 `domaincheck-node-agent`
- 重启本机 `domaincheck-api`
当前海外控制面 API 进程环境已确认是:
- `NODE_CODE=overseas-control-01`
- `NODE_REGION=overseas`
## 本轮已完成的关键修复
## A. 修复 controller node-agent 上报 localhost / 127.0.0.1
修改文件:
- [domain-api/app/node_agent.py](/www/wwwroot/getDomain/domain-api/app/node_agent.py)
修复内容:
- `_hostname()` 不再优先相信 `localhost`
- `_ip()` 不再使用容易得到 `127.0.0.1` 的旧逻辑
- 优先通过控制面地址推导本机出口 IP
- 回退时也会过滤 loopback
本轮新增/补过的测试:
- [domain-api/tests/test_node_agent_delivery_queue.py](/www/wwwroot/getDomain/domain-api/tests/test_node_agent_delivery_queue.py)
注意:
- 当前仓库里这份修复已经在真 controller 上生效
- handover 已显示:
- `agent_hostname = mainland-controller-01`
- `agent_ip = 121.204.244.188`
- `cluster_hostname = mainland-controller-01`
- `cluster_ip = 121.204.244.188`
## B. 修复 control 节点发布健康检查窗口过短
修改文件:
- [domain-api/app/services/ops_release_service.py](/www/wwwroot/getDomain/domain-api/app/services/ops_release_service.py)
修改目标:
- control 节点发布时,`domaincheck-api` 启动偏慢,旧健康检查窗口太短,会误判失败并回滚
代码里已改成:
- `health_check_timeout_seconds = 20`
- `health_check_retries = 6`
- `health_check_interval_seconds = 3`
但要注意一个坑:
- 这份代码虽然已改进源码
- 海外控制面的运行中 API 进程还没有通过这份新源码重新部署
- 所以 `smart-rollout-preview` 里看到的默认值一度仍然是旧的 `10 / 2 / 2`
因此本轮实际是通过“手工 remote-agent deploy job 显式带长窗口 payload”打通了 controller 发布。
## C. 真 controller 发布已经成功一次
成功任务:
- `job_id = 331`
- `job_code = ops-20260420183116-c33723`
- `action = deploy.release`
- `target_node_code = mainland-controller-01`
- `execution_mode = remote-agent`
- `status = success`
本次使用的 release
- `release_id = 27`
- `release_version = domaincheck_release_20260420_182916`
发布结果要点:
- 发布包下载成功
- checksum 校验成功
- `/opt/domaincheck/current` 切换成功
- `domaincheck-api / domaincheck-worker / domaincheck-sync-agent` 重启成功
- 健康检查最终通过
尤其要记住:
- 这次成功不是靠 smart rollout 默认值
- 是通过显式下发以下健康窗口打通的:
- `health_check_timeout_seconds = 20`
- `health_check_retries = 6`
- `health_check_interval_seconds = 3`
## D. controller node-agent 已经重新连回
后续又触发了:
- `job_id = 332`
- `action = service.restart`
- `payload.service_name = domaincheck-node-agent`
这个任务本身还停留在 `running`,原因很正常:
- node-agent 在“执行重启自己”的过程中会打断自身回执链
- 所以作业状态可能不会自然收尾
但实际效果已经发生:
- API 日志已看到 `121.204.244.188``2026-04-20 18:35:16` 重新开始:
- `POST /api/v1/ops/agent/heartbeat`
- `POST /api/v1/ops/agent/pull?limit=1`
因此这条 job 332 可以视为“结果已生效,但状态未优雅回写”的典型自重启任务。
## 当前实机状态
按最新控制面查询:
### mainland-controller-01
- `agent_online = true`
- `cluster_status = busy`
- `agent_hostname = mainland-controller-01`
- `agent_ip = 121.204.244.188`
- `current_load` 在本轮观察中约 `210 - 233`
- `detect_runtime.active_threads` 在本轮观察中约 `210 - 233 / 2000`
- 已经有持续日志回传
### mainland-worker-01
- node-agent 在线
- 但当前没有真正参与检测
- 控制面返回的 `detect_runtime` 错误为:
- `connection to server at "127.0.0.1", port 5432 failed: Connection refused`
这意味着:
- worker 机现在不是主要算力来源
- 目前真正吃任务的是 `mainland-controller-01`
## 当前主线瓶颈
目前主线已经不是“谁是 controller”了当前瓶颈明确是下面两个
1. `mainland-worker-01` 未恢复到可参与检测状态
2. `mainland-controller-01` 虽然真实线程已抬到 200+,但控制面队列视角仍存在:
- `claimed` 偏高
- `running/completed` 推进不够理想
- 吞吐没有完全吃透机器
也就是说:
- “节点身份问题”已基本打穿
- “发布链路问题”已基本打穿
- 下一步该只盯“真 controller 吞吐”和“worker 恢复”
## 本轮新增发现
### 1. mainland-worker-01 的 `127.0.0.1:5432` 更像是 node-agent 侧遥测链路问题
本轮继续排查后,发现这个问题至少有两层:
1. `domainCheck` 默认配置本身就是:
- `DB_HOST = localhost`
2. worker 机上的 `domaincheck-node-agent` systemd unit 当前只加载:
- `/etc/default/domaincheck-api`
- `/etc/default/domaincheck-node-agent`
但大陆 worker 快速安装脚本真正写入数据库与 Redis 指向的是:
- `/etc/default/domaincheck-worker`
也就是说worker 机上很可能出现这种情况:
- `domaincheck-worker` 进程拿到的是正确的 `DB_HOST=${MAINLAND_CONTROLLER_IP}`
-`domaincheck-node-agent` 没有继承 `/etc/default/domaincheck-worker`
- node-agent 内部去跑 `get_detect_status()` 时,就会落回 `domain-api` 默认配置:
- `db_host = 127.0.0.1`
于是控制面上看到的现象就变成:
- `mainland-worker-01 agent 在线`
-`detect_runtime` 里报:
- `connection to server at "127.0.0.1", port 5432 failed: Connection refused`
### 2. node-agent 当前把“DB 查询失败”和“worker 进程离线”混成了一种失败
`domain-api/app/node_agent.py` 里的 `_detect_runtime_snapshot()` 原来是:
- `get_detect_status()``detect_worker_runtime()` 放在同一个总 `try`
这会导致:
- 只要前面的 DB 查询失败
- 后面的 worker systemd 运行态也一起被吞掉
- 最终上报成:
- `worker_online = false`
- `service_running = false`
即使真实情况其实可能只是:
- worker 服务还活着
- 只是 node-agent 在采集 detect status 时查错 DB 了
### 3. 本轮已在源码里补的最小修复
已修改:
- [domain-api/app/node_agent.py](/www/wwwroot/getDomain/domain-api/app/node_agent.py)
- [domain-api/deploy/systemd/domain-node-agent.service](/www/wwwroot/getDomain/domain-api/deploy/systemd/domain-node-agent.service)
- [domain-api/tests/test_node_agent_delivery_queue.py](/www/wwwroot/getDomain/domain-api/tests/test_node_agent_delivery_queue.py)
修复内容:
1. `_detect_runtime_snapshot()` 改成分层降级:
- 先拿 `detect_worker_runtime()`
- 再单独尝试 `get_detect_status()`
- 即使 detect status 因 DB 异常失败,也保留真实的 worker service 运行态
2. `domaincheck-node-agent.service` 追加:
- `EnvironmentFile=-/etc/default/domaincheck-worker`
这样 worker 机上的 node-agent 也能直接继承 worker 真实使用的 `DB_HOST / REDIS_HOST`
### 4. 这次修复的生效边界
要特别注意:
- `node_agent.py` 代码修复可以通过常规 release 进入真实运行目录并生效
-`domaincheck-node-agent.service` 属于 `/etc/systemd/system/` 下的系统级 unit 文件
- 常规 `deploy.release` 只会切换 `/opt/domaincheck/current`,不会自动重装 systemd unit
所以这两项应分开看:
1. `node_agent.py`
- 可以走最小 release 先上真机
2. `domain-node-agent.service`
- 需要后续补 systemd unit 落地动作
- 至少要包含:
- 覆盖 unit 文件或 drop-in
- `systemctl daemon-reload`
- `systemctl restart domaincheck-node-agent`
### 5. 本轮测试结果
已通过的焦点测试:
- `PYTHONPATH=/www/wwwroot/getDomain/domain-api /opt/domaincheck/domainCheck/.venv/bin/python -m unittest tests.test_node_agent_delivery_queue -v`
结果:
- `11 tests`
- `OK`
新增验证点:
- `test_detect_runtime_snapshot_degrades_to_worker_runtime_when_detect_status_fails`
它验证了:
- 即使 `get_detect_status()` 抛出
- `connection to server at "127.0.0.1", port 5432 failed`
- node-agent 依然会保留:
- `worker_online = true`
- `service_running = true`
- `phase_detail = active/running`
## 本轮最小发布动作
### 1. 已生成新发布包
本轮最小修复已重新打包:
- `release_version = domaincheck_release_20260420_215734`
- `release_id = 28`
生成结果:
- `archive = /www/wwwroot/getDomain/release/domaincheck_release_20260420_215734.tar.gz`
- `sha256 = ad2c41625503dab1efaeadbf0641c8f6875a3cad0581a3b9c7835ccc37cdc718`
### 2. 已向真节点发起最小 release 下发
本轮只为把 `node_agent.py` 先推进真实运行目录,已创建:
- `job_id = 335`
- `target = mainland-controller-01`
- `action = deploy.release`
- `job_id = 336`
- `target = mainland-worker-01`
- `action = deploy.release`
这两条 job 都已经越过“等待拉取”,进入了 agent 执行阶段,并至少记录到:
- `executor_received`
- `deploy_download_started`
说明:
- 真 controller 和真 worker 都已经接到了这版最小 release
- 当前至少已经在真实节点上进入下载/发布链
### 3. 这次发布的真实目标
这次发布不是为了一次性解决所有 worker 恢复问题,而是为了先把下面这条代码修复推到真节点:
- `domain-api/app/node_agent.py`
目的:
- 即使 worker 节点的 `detect_status` 查询因 DB 指向错误失败
- node-agent 也不再把真实的 worker service 运行态一并吞掉
- 控制面能先看到更接近真实的 `worker_online / service_running`
### 4. 这次发布的限制
这次最小 release 暂时还不能自动完成下面这件事:
-`/etc/systemd/system/domaincheck-node-agent.service` 更新为新版本
原因:
- 常规 `deploy.release` 切的是 `/opt/domaincheck/current`
- 不会自动重装 systemd unit
因此当前判断是:
1. `node_agent.py` 代码修复:
- 已经进入真实节点发布链
2. `domaincheck-node-agent.service``EnvironmentFile=-/etc/default/domaincheck-worker`
- 仍需要后续单独补系统级落地动作
### 5. 当前发布观察结论
截至本次交接整理时:
- `job 335 / 336` 已启动执行
- 但尚未在本轮记录中拿到最终 `success / failed` 收尾结论
- 因此后续接手时,先做的第一件事之一,就是复查这两条 job 的最终状态与事件流
## 当前不要再踩的坑
### 1. 不要再把本机当成 mainland-controller-01
当前工作机是海外测试控制面,只负责:
- API
- 控制面
- 同步接收
不是 112 核大陆 controller。
### 2. 不要直接用本机 Python service 函数创建 deploy job
坑点:
- 直接在 shell 里跑本地 Python 服务函数时,读取到的 `settings.node_code` 可能不是运行中 API 进程的真实环境
- 之前就出现过把 job 错判为 `local-runtime` 的情况
正确做法:
- 优先通过“正在运行的 API HTTP 接口”创建 job
- 不要优先走本机 Python service 入口
推荐路径:
- `POST /api/v1/ops/releases/from-package/latest`
- `POST /api/v1/ops/jobs`
- `POST /api/v1/ops/jobs/{job_id}/dispatch`
### 3. 不要把 job 332 当成硬故障
`job 332``service.restart domaincheck-node-agent`
它卡在 `running` 不代表没生效,反而更像:
- node-agent 重启了自己
- 回执链没能把 job 收尾
判断是否真的生效,应看:
- API 日志里有没有来自 `121.204.244.188` 的 heartbeat/pull
- handover 里 `agent_hostname / agent_ip` 是否已刷新
### 4. 不要再回展示层
当前最值钱的推进方向仍然是:
- controller 真机吞吐
- claim/running/completed 推进
- worker 恢复
不要把额度再耗在页面、文案、展示层结构上。
## 这轮动过的关键文件
最关键的源码文件:
- [domain-api/app/node_agent.py](/www/wwwroot/getDomain/domain-api/app/node_agent.py)
- [domain-api/app/services/ops_release_service.py](/www/wwwroot/getDomain/domain-api/app/services/ops_release_service.py)
- [domain-api/tests/test_node_agent_delivery_queue.py](/www/wwwroot/getDomain/domain-api/tests/test_node_agent_delivery_queue.py)
此外,工作区还存在大量其他未提交改动,不要随意回滚:
- `domain-api/`
- `domain-web/`
- `domainCheck/`
- `docs/ops_center_runtime/`
这是一个脏工作区,接手时必须小心,不要用破坏性 git 命令。
## 建议下一个 Codex 只做的两件事
### 任务 1恢复 mainland-worker-01
目标:
-`mainland-worker-01` 从“agent 在线但不参与检测”恢复到可执行检测
先查方向:
- 为什么它在本地检测态里访问 `127.0.0.1:5432` 失败
- 是本机 PostgreSQL 没启
- 还是 worker 的运行配置仍然错误指向本地 DB
- 还是它本来就不该走本地 PostgreSQL而应走远端/统一控制链
验收标准:
- `mainland-worker-01.detect_runtime.worker_online = true`
- `mainland-worker-01.detect_runtime.active_threads > 0`
- 能稳定进入参与节点
### 任务 2继续抬 mainland-controller-01 真吞吐
目标:
- 只盯真 controller 的任务推进链,不碰页面
重点看:
- `claimed -> running -> completed` 是否持续推进
- `items_claimed` 是否能下降
- `processed_recent / processed_per_minute` 是否能抬起来
- `active_threads``completed` 是否成正相关
验收标准:
- controller 持续有真实 completed 增长
- running/claimed 更贴近“持续补位”而不是堆积
- 机器性能使用能继续往上抬
## 可直接复用的验证点
### 1. 看节点 handover
接口:
- `GET /api/v1/ops/nodes/mainland-controller-01/handover`
这一项已经能确认:
- 当前是不是对到了真 controller
- agent/ip/hostname 是否正确
- 当前 load / detect_runtime 是否在动
### 2. 看节点列表
接口:
- `GET /api/v1/ops/nodes`
重点字段:
- `agent_hostname`
- `agent_ip`
- `cluster_hostname`
- `cluster_ip`
- `detect_runtime.active_threads`
- `current_load`
### 3. 看海外控制面 API 日志
已验证有效:
- `journalctl -u domaincheck-api -n 200 --no-pager`
尤其可以筛:
- `121.204.244.188`
- `/api/v1/ops/agent/heartbeat`
- `/api/v1/ops/agent/pull`
### 4. 发布 controller 的正确方式
推荐继续使用运行中的 API HTTP 接口,而不是本地 Python service 调用。
## 交接结论
这一轮真正解决掉的,不是“性能问题”本身,而是它前面最大的认知阻塞:
- 之前一直有一部分判断建立在“本机就是 controller”这个错误前提上
- 现在这个前提已经纠正
- 真 controller 已经重新纳入控制面,而且身份上报正确、远端发布成功、线程也已经真实抬起来
接手人从这里继续时,应该把主线收缩成一句话:
“只盯 `mainland-controller-01` 的真实吞吐推进,并恢复 `mainland-worker-01`,不要再回展示层,也不要再把海外 12 核测试机当成主算力机。”

View File

@@ -0,0 +1,483 @@
# IMPLEMENTATION_STATUS
更新时间2026-04-19 21:25 CST
## 当前真实状态
阶段判断:
- 海外单脑接管能力:约 `97%`
- 发布闭环真实可用度:约 `65%~70%`
- 分布式检测真实执行能力:约 `80%~85%`
- 距离“可稳定上线并放心用后台发起检测”:约 `78%~82%`
## 21:17 最新校正
刚完成的 `mainland-worker-01` 正式 rollout 已给出最终根因:
- `job 211 / rollout 6 / release 7`
- 发布包下载成功
- release 解压成功
- `current` 软链切换成功
- 最终失败在服务重启:
- `restart failed: domaincheck-worker`
- `Failed to restart domaincheck-worker.service: Interactive authentication required.`
这说明:
- 当前 ReleaseHub 主链路本身已可推进到“切换 current”
- 真正未闭环的是 mainland node-agent 的 systemd 权限
- 只要 node-agent 仍以 `www` 运行,后续 `deploy.release / service.restart` 都会在 systemd 这一跳失败
已完成的代码侧修正:
- `domain-api/deploy/systemd/domain-node-agent.service`
- 改为 `User=root`
- 改为 `Group=root`
- `domain-api/deploy/multi-region/fix_mainland_release_base.sh`
- 改为给 node-agent drop-in 写入 `User=root` / `Group=root`
因此当前真实上线完成度需要再补一句校正:
- 发布闭环真实可用度:
- 不是“发布包模型还没修”
- 而是“node-agent 权限模型还差最后一次现网切换”
## 21:25 最新进展
worker 侧的现网切换已经完成验证成功:
- `mainland-worker-01`
- 已把 `domaincheck-node-agent` 切为 `root`
- 随后重新发起:
- `rollout_id = 7`
- `job_id = 214`
- 最终结果:
- `job 214 = success`
- `rollout 7 = completed`
正式成功证据:
- `agent_completed`
- `summary_text = release deployed`
- `restart_results[domaincheck-worker].returncode = 0`
- `health_check.ok = true`
- `systemd ExecStart` 已对齐:
- `/opt/domaincheck/current/domainCheck/detect_worker.py`
因此当前关于发布闭环的真实判断应更新为:
- worker 发布闭环:
- 已从“卡在 systemd restart 权限”推进到“真实成功”
- 当前剩余风险不再在 worker
- 当前剩余预防项在 controller
- `domaincheck-node-agent` 也应同步切为 `root`
## 顶部校正
今天晚上的最新结论,需要覆盖前面一部分偏乐观判断:
- 最新发布包问题已经定位并修复:
- 之前发布包漏掉了 `domainCheck/`
- 现在最新签收包 `domaincheck_release_20260419_205437` 已经包含 `domainCheck/`
- 但对 `mainland-worker-01` 的正式发布验证证明:
- 线上 mainland 节点目前还不满足现有 ReleaseHub 发布模型
- 已确认的真实阻塞有两个:
- `deploy.release``mainland-worker-01` 上会因为
- `Permission denied: /opt/domaincheck/downloads`
- 而直接失败
- mainland 两台节点当前 `domaincheck-worker``ExecStart` 都直接指向:
- `/opt/domaincheck/domainCheck/detect_worker.py`
- 而不是 `/opt/domaincheck/current/domainCheck/detect_worker.py`
这两个事实组合起来说明:
- 当前发布链虽然在控制面上已经成型
- 但 mainland 线上节点的安装形态还是旧模式
- 所以当前不能再把“已能稳定 rollout 新版本”算进上线完成度
## 今晚新增硬证据
- `mainland-worker-01`
- `job 204 / rollout 5` 已正式失败回写
- 失败原因已收口为:
- `install_root not writable: /opt/domaincheck/downloads`
- 只读核验得到的实际服务状态仍是旧进程:
- `Active since Sun 2026-04-19 18:18:50 CST`
- `Main PID = 635924`
- `CPU = 18.994s`
- 说明 worker 当前并没有切到新包,也没有形成可信的新吞吐样本
- `mainland-controller-01`
- 当前 `domaincheck-worker` 虽然在高负载运行
- 但服务启动路径同样是:
- `/opt/domaincheck/domainCheck/detect_worker.py`
- 说明 controller 也没有对齐 `current` 软链发布模型
## 本轮代码侧新增收口
- 已补齐发布包构建:
- `package_domain_release.sh`
- `verify_domain_release.sh`
- `package_domain_release.ps1`
- `verify_domain_release.ps1`
- 现在发布包会包含 `domainCheck/`
- 已补齐发布执行器的失败可观测性:
- `domain-api/app/services/ops_release_executor_core.py`
- 现在会在发布目录不可写时显式返回失败结果
- 同时补充 `ExecStart``current` 软链的对齐观测
- 已补齐 node-agent 的兜底失败回写:
- `domain-api/app/node_agent.py`
- 避免以后再出现任务已经炸掉但控制面一直卡在 `running`
## 本轮最新结论
新增结论:
- 检测页观察面已完成一轮线上收口:
- `任务日志控制台` 已移到事件表上方
- `检测事件流` 已改成独立滚动区
- 已在真实线上静态目录重建生产包并通过本机 `3201` 端口验证
- 当前如果用户仍看到旧布局,优先判断为浏览器缓存而不是部署未生效
- 代理链已完成策略切换:
- worker 启动后会主动刷新代理池
- 配置更新后也会主动刷新代理池
- 后台已能区分:
- `等待首刷`
- `proxy_validation_zero`
- `直入池`
- 当前本机最新真实结果是:
- 原始代理 `270`
- 预验证 `0`
- 直入池 `270`
- 说明当前问题已经从“代理校验过严导致池为空”切换为“真实任务内动态淘汰失效代理”
- `mainland-controller-01`
- 已确认解除“代理不足即同步刷新、反向压死并发”的旧限制
- 海外后台当前已能看到:
- `active_threads = 99~100`
- `max_threads = 100`
- 说明 controller 的 `100` 并发已经真实生效
- `mainland-worker-01`
- 已重新部署最新版 `detect_worker.py`
- 已重新接收新的 `sync-pull` 批次并重进检测:
- `开始执行域名检测任务`
- `开始检测,刷新代理池`
- `代理池刷新完成,共 23 个可用代理`
- `开始创建线程,当前批次域名数: 400最大线程数: 50`
- 当前 worker 进程本机线程量已到:
- `152` 个 OS 线程
- 说明它并不是没启动,而是已经进入新批次执行
- 当前剩余偏差:
- overseas 后台对 `mainland-worker-01.active_threads/current_load` 的显示仍偏低
- 这已经从“真实执行问题”收敛为“运行态上报 / 显示口径问题”
这一轮不是只修了显示问题,而是把“大陆节点真实执行 + worker 日志回传”一起补齐了。
当前最新结论:
- controller 的 `pull_tasks -> 本地队列` 断点已经修通
- 两台大陆 worker 都已经进入真实镜像队列执行
- `mainland-worker-01``worker_log` 已开始直接回灌 overseas `detect_debug_events`
- `runtime_projection` 权限问题已经修复,后台运行态同步恢复
- `/api/v1/ops/nodes` 已能证明 controller 的高并发真实生效
- 当前剩余问题已经收敛为:
- `mainland-worker-01` 运行态显示口径仍需继续对齐
- 检测页主计数口径是否完全跟上
- 结果统计回推是否持续稳定
## 当前证据拆分
### 1. 代码闭环
已经完成:
- `sync_push_service.ingest_detect_task_projection`
- 不再只导入 `domains`
- 已改为同时创建本地 `detect_jobs`
- 已改为同时创建本地 `detect_job_items`
- 已把 `target_job_id / target_job_code / queued_count / worker_start_ok` 回写到同步结果
- `sync_agent`
- controller 现在会在每轮 `pull_tasks` 后自动唤起本地 worker
- `detect_worker._set_active_cycle_context`
- 已兼容 `sync-pull` 控制消息
- 不再只读取 `job_id / job_code`
- 现在会回退读取 `target_job_id / target_job_code`
- 运行态同步链
- controller `runtime/detect_runs.json` 权限已修正为 `www:www`
- `runtime_projection` 已恢复成功推送
本地代码验证已通过:
- `python -m py_compile domain-api/app/services/sync_push_service.py`
- `python -m py_compile domain-api/app/services/runtime_control_service.py`
- `python -m py_compile domain-api/app/sync_agent.py`
- `python -m py_compile domainCheck/detect_worker.py`
### 2. 接管 / 外部条件闭环
已经完成:
- `remote_access_ready = 3/3`
- `ssh_ready = 2`
- 大陆 controller / worker 都可远程运维
- controller `domaincheck-sync-agent` 在线
- mainland 两台 `domaincheck-node-agent` 在线
当前仍依赖你额外输入的部分:
- 暂无新的 SSH / 接管前置输入缺口
- 如果页面仍显示旧状态,最多只需要你浏览器强刷确认,不需要再补 SSH 信息
### 2.1 前端部署闭环
已经完成:
- 在线静态根目录确认:
- `/www/wwwroot/getDomain/domain-web/dist`
- 在线 Nginx 配置确认:
- `/www/server/panel/vhost/nginx/domaincheck_3201.conf`
- `/www/server/panel/vhost/nginx/domaincheck_152.53.37.118.conf`
- 生产包重建确认:
- `vite build` 成功
- 线上资源确认:
- `DetectView-B9S1WMRT.js`
- `DetectView-BFxMNRNR.css`
说明:
- 检测页布局调整不是只停留在源码
- 已经进入线上可访问静态产物
### 2.2 代理运行态闭环
已经完成:
- worker 启动即触发代理池首刷
- 配置变更后自动补刷
- API 状态页已能准确显示:
- `proxy_not_refreshed_yet`
- `proxy_validation_zero`
- `宽松入池`
当前最新证据:
- `proxy_last_refresh_status = 直入池 270 个(跳过预验证)`
- `proxy_last_refresh_total_items = 270`
- `proxy_last_validated_count = 0`
- `proxy_last_available_count = 270`
说明:
- 代理配置本身已成功下发
- 代理源接口本身也能返回大量原始代理
- 当前不再把“预验证是否通过”作为入池门槛
- 现在改为让真实检测来完成失效代理淘汰
### 3. 检测执行闭环
这一块现在已经从“怀疑恢复”进入“确认恢复”:
- `mainland-controller-01`
- 已出现:
- `从任务队列获取到 800 个需要检测的域名`
- `最大线程数: 100`
- `当前实际线程数量: 1/100 ... 6/100`
- `mainland-worker-01`
- 已出现:
- `从任务队列获取到 400 个需要检测的域名`
- `开始创建线程,当前批次域名数: 400最大线程数: 50`
- `当前实际线程数量: 1/50 ... 3/50`
- `开始检测域名: 0-demagogo.com`
- `开始检测域名: 00123321.com`
- `开始检测域名: 001dm.com`
这说明:
- `100/50` 已不是“配置已写入但没生效”
- 它已经进入真实任务消费
- worker 的远端日志也已经跟着真实执行一起回传
### 4. 海外后台可视证据
`/api/v1/ops/nodes` 当前已显示:
- `summary.remote_access_ready = 3`
- `summary.participating = 3`
- `summary.dispatch_active = 1`
并且大陆两台都已经被判定为真实参与者:
- `mainland-controller-01`
- `agent_state = online_busy`
- `participation_state = recent_throughput`
- `processed_recent = 115`
- `processed_per_minute = 7.67`
- `detect_runtime.max_threads = 100`
- `mainland-worker-01`
- `agent_state = online_busy`
- `participation_state = recent_throughput`
- `processed_recent = 632`
- `processed_per_minute = 42.13`
- `detect_runtime.max_threads = 50`
这说明:
- 海外后台已经不只是看到“在线”
- 现在已经能看到大陆节点的实际吞吐
## 本轮新增硬证据
### 证据 1controller 的镜像队列已经真正落库
`sync-agent` 现场日志已出现:
- `target_job_code = sync-overseas-7380`
- `queued_count = 200`
- `worker_start_ok = True`
并持续产生:
- `sync-overseas-7383`
- `sync-overseas-7386`
- `sync-overseas-7392`
- `sync-overseas-7417`
说明:
- 大陆 controller 现在不是只拉数据
- 而是在持续形成可执行批次
### 证据 2两台大陆 worker 都已转入真实队列
现场日志已明确出现:
- controller
- `从任务队列获取到 800 个需要检测的域名`
- worker
- `从任务队列获取到 400 个需要检测的域名`
说明:
- 当前不是兼容旧链路假运行
- 是镜像队列真运行
### 证据 3runtime_projection 已恢复成功
修复前:
- `refresh runtime_projection failed: [Errno 13] Permission denied`
修复后:
- 最新 `sync-agent` 日志已出现:
- `sync_state = success`
- `runtime_projection -> 投影推送成功`
说明:
- 后台运行态刷新和日志窗口不再被 controller 本地权限卡死
### 证据 4`mainland-worker-01` 的 `worker_log` 已进入 overseas
`/api/v1/runtime/debug-events` 当前已能看到:
- `mainland-worker-01 -> 开始执行检测任务,来源: redis-control`
- `mainland-worker-01 -> 开始执行域名检测任务,正在加载配置`
- `mainland-worker-01 -> 开始检测,正在刷新代理池`
- `mainland-worker-01 -> 代理池刷新完成,共 7 个可用代理,来源链接 6 个,原始 265 个,验证 150 个`
- `mainland-worker-01 -> 从任务队列获取到 400 个需要检测的域名`
- `mainland-worker-01 -> 开始创建线程,当前批次域名数: 400最大线程数: 50`
- `mainland-worker-01 -> 当前实际线程数量: 1/50`
- `mainland-worker-01 -> 当前实际线程数量: 2/50`
- `mainland-worker-01 -> 当前实际线程数量: 3/50`
说明:
- worker 的真实执行链已经进入 overseas 的日志视图
- “后台看不到大陆 worker 在干活”这一层已经闭合
## 当前口径说明
这里有一个非常关键的判断口径已经变化:
- 大陆节点当前执行的是“海外任务在大陆本地落镜像队列,再把运行态和结果同步回海外”
- 因此不能再只盯中央原生 `detect_job_items.claimed/running`
- 现在应该同时看:
- `/api/v1/ops/nodes`
- `processed_recent`
- `processed_per_minute`
- `detect_runtime.active_threads/max_threads`
- 大陆 controller 本地 `sync-overseas-*` 队列
如果只看中央原生队列,会误判“大陆没有参与”。
## 当前已闭合的问题
已闭合:
- controller `pull_tasks` 只导入 domain、不导入本地队列
- 大陆 worker 长时间卡在旧检测会话导致忽略新启动指令
- controller `runtime_projection` 因文件属主错误无法推送
- 大陆两台“在线但不确定是否真实执行”的状态模糊
## 当前剩余问题
当前剩余问题已经缩成两个最小项:
- Detect 页面主计数 `pending/completed/running` 是否继续推进
- 结果统计回推是否稳定,而不只是日志链路先恢复
换句话说:
- 现在不是接管问题
- 不是链路不通问题
- 不是日志完全回不来问题
- 而是最后一层“主计数推进 + 结果统计收口”问题
## 当前是否可以继续跑检测测试
当前结论:
- 可以继续跑检测测试
- 而且现在已经具备“后台可观测 + 大陆真实参与”的条件
## 当前是否建议直接上线
当前结论:
- 已接近可上线状态
- 但我仍建议把它视为“准上线收口态”,不是最终完全签收态
原因:
- 主执行链已经恢复
- 但还需要再确认 1 到 2 个同步周期内页面口径与吞吐稳定性
## 当前优先级判断
最高优先级:
- `J2-检测执行收口批`
当前不应继续推进:
- 新控制面功能
- 新模块
- 新页面
- 发布动作
- 与检测执行收口无关的工作
## 完成下一轮后的预期
如果下一轮确认:
- Detect 页面主计数已跟上
- 日志窗口持续刷新
- `detect_result_projection` 持续推进
- `processed_recent / processed_per_minute` 持续增长
则整体可上线程度预计可提升到:
- `96%~98%`
在那之前,当前口径应保持保守。

View File

@@ -0,0 +1,41 @@
# NIGHT PACKAGE 2026-04-19 01:21
执行窗口:
- 开始时间:`2026-04-19 01:21 CST`
- 截止时间:`2026-04-20 12:00 CST`
范围边界:
- 只围绕当前收口目标执行
- 不进入新实现
- 不扩展控制面功能
- 不新增页面、模块或专题文档
夜间任务包内容:
1. 周期性复查:
- `go-live-summary`
- `stack-diagnosis`
- `release-launchpad`
- `playbook-runs`
- `overseas-control-01 scene-log`
2. 若日志样本再次出现缺口:
- 自动执行 `log-sync-recover`
- 自动执行一次 `run_inspection_participating`
3. 若只剩历史 `playbook_runs_need_attention`
- 最多补 3 轮安全的 `inspection.standard`
- 目的仅为刷新近期成功 run推动历史告警窗口收敛
4. 到达以下任一条件即停止:
-`2026-04-20 12:00 CST`
- 或者:
- `log_sync_state = full_capture`
- `issue_total = 0`
- `problem_runs_total = 0`
输出位置:
- 运行日志目录:
- [docs/ops_center_runtime/night_runs](/www/wwwroot/getDomain/docs/ops_center_runtime/night_runs)
- 停止后自动生成报告:
- `night_run_*_report.md`

View File

@@ -0,0 +1,564 @@
# TASK_BOARD
更新时间2026-04-19 21:25 CST
## 2026-04-20 主线切换说明
从这一刻开始,当前工作重心正式切回:
- 先跑通主任务流程
- 先推进 7 个大任务的测试与验收
- 并发、代理、DB 往返、展示层等细节优化先封存,不再抢主线
细节优化不删除,统一视为 backlog
- worker pool 持续补位
- claimed 回弹压缩
- 高频 DB 更新继续合并
- 代理失败链和等待窗口继续压缩
- 运营视角页面继续细化
这些后续继续做,但不再打断主任务验收顺序。
当前主口径:
1. 大任务 1 真实验收闭环
2. 大任务 2 controller 编排闭环
3. 大任务 3 统一结果状态机闭环
4. 大任务 4 本地控制状态 + syncer/finalizer 闭环
5. 大任务 5 固定 worker pool 落地
6. 大任务 6 时光机一期接入
7. 大任务 7 运营视角面板闭环
## 21:17 最新补充
刚刚这轮真实 rollout 已经把 mainland worker 的最后一层阻塞拿实:
- `mainland-worker-01`
- `release_id = 7`
- `rollout_id = 6`
- `job_id = 211`
- 发布链路并不是卡在下载或解压:
- 发布包 `domaincheck_release_20260419_205437` 已下载到 `/opt/domaincheck/downloads`
- release 已解压到 `/opt/domaincheck/releases/domaincheck_release_20260419_205437`
- `/opt/domaincheck/current` 已切到新 release
- 最终失败点已经明确:
- `restart failed: domaincheck-worker`
- systemd 原因:
- `Interactive authentication required`
- 这说明当前 mainland 节点的 `domaincheck-node-agent` 虽然能写发布目录,但因为以 `www` 身份运行,无法执行:
- `systemctl restart domaincheck-worker`
当前新的唯一主阻塞已经进一步收敛为:
- node-agent systemd 运行身份不对
- 需要把 `domaincheck-node-agent` 改成 `root` 运行,发布链最后一跳才能闭环
本轮已在仓库内同步修正:
- `domain-api/deploy/systemd/domain-node-agent.service`
- `User=root`
- `Group=root`
- `domain-api/deploy/multi-region/fix_mainland_release_base.sh`
- node-agent drop-in 现在也会显式写入:
- `User=root`
- `Group=root`
## 21:25 worker rollout 收口
`mainland-worker-01` 已完成新一轮正式 rollout 收口成功:
- `release_id = 7`
- `rollout_id = 7`
- `job_id = 214`
结果确认:
- `job 214 = success`
- `rollout 7 = completed`
- `mainland-worker-01` 已恢复为:
- `agent_state = online_busy`
- 最近心跳恢复正常
控制面完成证据:
- `agent_completed`
- `summary_text = release deployed`
- `restart_results`
- `domaincheck-worker.returncode = 0`
- `health_check.ok = true`
- `execstart_alignment.mismatched_services = []`
这说明 worker 当前已经真正完成:
- 新包下载
- release 解压
- `current` 切换
- `domaincheck-worker` 重启
- 健康检查通过
当前关于 mainland rollout 的唯一剩余预防项变成:
- `mainland-controller-01` 也应该同步把 `domaincheck-node-agent` 切到 `root`
- 否则后续 controller 自身执行 `deploy.release / service.restart` 时还会踩到同类 systemd 权限问题
## 顶部校正
今天晚上的最新排查已经把当前主阻塞重新定性,之前“大陆两台已经完全进入统一新镜像执行”的判断需要收紧。
当前新增硬结论:
- 最新正式发布包已经重打并签收通过:
- `domaincheck_release_20260419_205437`
- 发布包现在已经确实包含 `domainCheck/`
-`mainland-worker-01` 发起正式 smart rollout 后,真实失败原因已经拿到:
- `job 204 / rollout 5`
- 本次失败对应的正式 Release 版本仍是:
- `domaincheck_release_20260419_203933`
- 失败原因:
- `Permission denied: /opt/domaincheck/downloads`
- 该失败已通过正式 agent complete 回写,后台不再是假 `running`
- `mainland-worker-01` 当前运行中的 `domaincheck-worker` 仍是旧进程:
- `Main PID = 635924`
- `Active since = 2026-04-19 18:18:50 CST`
- `CPU = 18.994s`
- 说明它不是高吞吐新进程,而是老进程长期挂着
- `mainland-controller-01` 当前运行中的 `domaincheck-worker` 虽然活跃,但服务启动路径同样是:
- `/opt/domaincheck/domainCheck/detect_worker.py`
- 两台 mainland 节点当前 `domaincheck-worker` 的 systemd 启动路径都不是:
- `/opt/domaincheck/current/domainCheck/detect_worker.py`
这意味着:
- 当前 ReleaseHub 的 `current -> release_version` 切换模型,与线上 mainland 节点的实际服务启动路径不一致
- 即使发布包和签收链已经修好,线上节点也还没有具备“按当前发布模型热切版本”的条件
- 当前唯一主阻塞已经从“并发参数是否下发”切换成:
- mainland 节点发布权限/目录模型不匹配
- mainland 节点服务启动路径与发布模型不匹配
## 当前主批次
唯一主批次:`J2-检测执行收口批`
目标:
- 不进入新页面
- 不扩展控制面
- 不新增发布动作
- 只收口三件已经缩小到运行面的事情:
- 大陆节点必须真正进入统一镜像队列,而不是停留在兼容旧链路
- 后台必须能看到大陆节点的实时运行态与日志
- `100/50` 并发配置要从“已下发”推进到“真实有参与吞吐”
## 本轮最新状态
### 20:53 最新阻塞结论
- `mainland-worker-01` smart rollout 已真实失败,不再继续误判为执行中
- 失败证据:
- node-agent 日志:
- `2026-04-19 20:40:15 [node-agent] loop error: [Errno 13] Permission denied: '/opt/domaincheck/downloads'`
- 发布任务:
- `job 204 = failed`
- 发布批次:
- `rollout 5 = failed`
- 当前不应该继续把精力放在前端展示或并发口径微调上
- 当前必须先收口:
- mainland 节点 `deploy.release` 所需目录权限
- mainland 节点 systemd `ExecStart``/opt/domaincheck/current` 的一致性
这轮已经完成从“控制链打通”到“真实执行恢复 + worker 日志回传恢复”的关键跨越。
### 本轮前端已上线校验
- 检测页 `任务日志控制台` 已调整到事件列表上方
- `检测事件流` 已改成独立滚动区:
- 表格 `max-height = 320`
- 避免事件越积越多把整个页面继续向下撑长
- 已在线上实际静态目录重新构建:
- `/www/wwwroot/getDomain/domain-web/dist`
- 已确认线上 Nginx 指向该目录:
- `domaincheck_3201.conf`
- `domaincheck_152.53.37.118.conf`
- 已通过 `http://127.0.0.1:3201/` 返回 `200` 且加载新资源:
- `DetectView-B9S1WMRT.js`
- `DetectView-BFxMNRNR.css`
### 本轮代理链已收口
- 已修复 worker 在“代理配置已下发但尚未开始检测”时长期停留 `未刷新` 的问题
- `domaincheck-worker` 现在会在以下时机主动触发代理池刷新:
- worker 启动后
- `proxy_config / thread_count / node_thread_counts / runtime_settings` 更新后
- 当前后台状态已不再误报“未刷新”
- 代理策略已切到:
- 只去掉过期 / 非法代理
- 跳过预验证
- 直接入池执行
- 真实失败后立即淘汰并补刷
- 最新实测结果已经明确:
- 原始代理 `270`
- 预验证 `0`
- 当前可用代理 `270`
- 最近状态:
- `proxy_last_refresh_status = 直入池 270 个(跳过预验证)`
- `available_proxy_count = 270`
### 本轮已完成
- `sync_push_service`
- 已修复 `detect_task_ingest` 只落 `domains`、不落本地 `detect_jobs/detect_job_items` 的缺口
- controller 现在会为拉回来的海外批次持续创建本地镜像任务:
- `sync-overseas-7380`
- `sync-overseas-7383`
- `sync-overseas-7392`
- 持续增长中
- `mainland-controller-01`
- 已重启 `domaincheck-worker`
- 已明确进入真实队列:
- `从任务队列获取到 800 个需要检测的域名`
- `最大线程数: 100`
- `当前实际线程数量: 1/100 ... 6/100`
- `mainland-worker-01`
- 已修复 `sync-pull` 控制消息上下文绑定缺口:
- `detect_worker._set_active_cycle_context` 现在会读取
- `target_job_id`
- `target_job_code`
- 已重启 `domaincheck-worker`
- 已明确进入真实队列:
- `从任务队列获取到 400 个需要检测的域名`
- `最大线程数: 50`
- `当前实际线程数量: 1/50 ... 3/50`
- 已明确把运行日志回传到 overseas
- `开始执行检测任务,来源: redis-control`
- `开始执行域名检测任务,正在加载配置`
- `开始检测,正在刷新代理池`
- `开始创建线程,当前批次域名数: 400最大线程数: 50`
- `当前实际线程数量: 1/50`
- `当前实际线程数量: 2/50`
- `当前实际线程数量: 3/50`
- `runtime_projection`
- 已定位 controller `domain-api/runtime/detect_runs.json` 权限错误
- 已把 `runtime` 目录和 `detect_runs.json` 改回 `www:www`
- `domaincheck-sync-agent` 最新日志已从
- `partial_success`
- 变成:
- `sync_state = success`
- `runtime_projection -> 投影推送成功`
- 海外控制面 `/api/v1/ops/nodes`
- 现已明确看到三台节点都在参与
- `remote_access_ready = 3`
- `participating = 3`
- `mainland-controller-01.is_current_participant = true`
- `mainland-worker-01.is_current_participant = true`
### 当前最关键的新证据
- `mainland-controller-01`
- `processed_recent = 115`
- `processed_per_minute = 7.67`
- `detect_runtime.max_threads = 100`
- `mainland-worker-01`
- `processed_recent = 632`
- `processed_per_minute = 42.13`
- `detect_runtime.max_threads = 50`
- `overseas-control-01`
- 仍在执行中央原生队列
- 当前判断:
- 大陆节点已经不是“纸面在线”
- 已经是真实参与检测执行
## 当前主判断
### 本轮新增结论
- `mainland-controller-01`
- 已修复“代理数量不足反向限制并发”的热路径问题
- 当前海外后台已稳定看到:
- `active_threads ~= 99~100`
- `max_threads = 100`
- 说明 `100` 并发不再只是配置已下发,而是已进入真实运行态
- `mainland-worker-01`
- 已重新部署同版 `detect_worker.py`
- 已重新接收到新的 `sync-pull` 批次:
- `source_record_id = 7679`
- `target_job_code = sync-overseas-7679`
- 已完成代理抽样校验并进入:
- `开始创建线程,当前批次域名数: 400最大线程数: 50`
- 当前剩余问题已经缩成:
- worker 本机已启动新批次并创建线程
- 但海外后台对 `mainland-worker-01.active_threads` 的显示仍偏低,和本机进程线程量不完全一致
### 当前唯一剩余收口点
- 不再是 controller 并发限制问题
- 当前唯一剩余收口点变成:
- `mainland-worker-01` 的运行态上报口径仍需继续和真实执行量对齐
- 以及检测主计数 `pending/completed/running` 继续推进
### 已经收口的部分
- 大陆节点不再停留在 `pending_bootstrap`
- Agent + SSH 接管已经完成
- `sync-agent pull_tasks` 已经真正生成本地镜像队列
- 两台大陆 worker 已经真正吃到 `detect_job_items`
- 后台运行态同步链已经恢复
### 当前剩余问题
- Detect 页面日志窗口已经不再是单节点
- `/api/v1/detect/status` 已出现:
- `remote_log_node_count = 2`
- `remote_log_nodes = ["mainland-controller-01", "mainland-worker-01"]`
- 当前剩余问题缩成一个最小点:
- 检测页主计数 `pending/completed/running` 还没有跟着这轮大陆执行立即推进
- 前端布局问题已收口,后续不再停留在“页面结构挡住观察”
- 代理链当前也已收口到真实口径,不再停留在“配置有了但没刷新”
- 下一步应继续观察这 `270` 个直入池代理在真实检测里的淘汰速度与吞吐提升
- 现在更应该同时看:
- `/api/v1/detect/status`
- `/api/v1/runtime/debug-events`
- `/api/v1/ops/nodes`
- worker `current actual threads` 日志
## 下一步唯一主批次
唯一主批次保持为:`J2-检测执行收口批`
下一步只做:
- 继续观察 Detect 页面主计数是否跟上最新运行态
- 继续确认 `detect_result_projection` / 结果统计回推是否稳定推进
- 继续收口 `mainland-worker-01` 的运行态上报,使后台显示与本机真实线程量一致
- 若仍有显示偏差,只修统计/上报口径,不新扩功能
## 候选批次
### Candidate J3
名称:结果计数收口批
进入条件:
- 节点已经真实执行
- 日志窗口已经恢复
- 但 Detect 页面主计数仍不前进
只做:
- 复核 `detect_result_projection`
- 复核结果统计回推
- 不改控制面结构
### Candidate J4
名称:吞吐稳定性观察批
进入条件:
- 页面口径已恢复
- 继续确认大陆两节点吞吐是否稳定,不再回落
只做:
- 继续观察 `processed_recent`
- 继续观察代理池质量
- 继续观察 `active_threads/max_threads`
## 暂停项
以下任务现在不应继续推进:
- 新页面
- 新模块
- 新发布动作
- 新专题文档
- 与检测执行收口无关的控制面增强
## 关键证据
### 证据 1镜像队列已经落地
controller `sync-agent` 最新 `task pull tick` 已出现:
- `target_job_id`
- `target_job_code`
- `queued_count = 200`
- `worker_start_ok = True`
说明:
- controller 现在不是只同步域名
- 而是在本地持续创建可执行队列
### 证据 2大陆 worker 已进入真实队列
现场日志已经明确出现:
- `mainland-controller-01 -> 从任务队列获取到 800 个需要检测的域名`
- `mainland-worker-01 -> 从任务队列获取到 400 个需要检测的域名`
说明:
- “并发没起来”的主要根因已经修正
- 它们不是在跑旧兼容链路
### 证据 3运行态同步已恢复
controller `sync-agent` 最新日志已经出现:
- `sync_state = success`
- `runtime_projection -> 投影推送成功`
说明:
- 后台运行态/日志窗口链路已经不再被权限错误卡死
### 证据 4海外 `/ops/nodes` 已把大陆节点判定为真实参与者
当前海外控制面已经显示:
- `mainland-controller-01`
- `online_busy`
- `is_current_participant = true`
- `processed_recent = 115`
- `mainland-worker-01`
- `online_busy`
- `is_current_participant = true`
- `processed_recent = 632`
说明:
- 现在大陆两台都已进入真实参与态
- 下一步不再是接管问题,而是页面口径与吞吐稳定性问题
### 证据 5Detect 页面远端日志已恢复双节点
当前 `/api/v1/detect/status` 已显示:
- `remote_log_node_count = 2`
- `remote_log_nodes = ["mainland-controller-01", "mainland-worker-01"]`
最近日志样本已出现:
- `mainland-worker-01 -> 从任务队列获取到 400 个需要检测的域名`
- `mainland-worker-01 -> 开始创建线程,当前批次域名数: 400最大线程数: 50`
- `mainland-worker-01 -> 当前实际线程数量: 1/50`
- `mainland-worker-01 -> 当前实际线程数量: 2/50`
- `mainland-worker-01 -> 当前实际线程数量: 3/50`
说明:
- worker 不再是“只在节点本地运行、页面看不到”
- 检测页日志链已经真正接上 mainland worker
### 证据 6full_capture 已开启,但源日志时间没有继续前进
节点现场日志最新可见记录仍停在较早时间:
- `mainland-controller-01`
- 最近样本集中在 `01:00:23`
- `mainland-worker-01`
- 最近样本集中在 `01:00:35`
额外 35 秒观察窗口结果:
- `capture_at` 没有继续前进
- `source_msg` 里的源日志时间也没有继续前进
说明:
- 不是“全量日志没开”
- 也不是“日志回传没回来”
- 而是执行进程这段时间确实没有继续产生日志
### 证据 7worker 控制消息补偿链已在线上验证生效
之前运行态存在一个真实风险:
- `runtime.start_detection` 成功只代表“控制消息已发布到 Redis”
- 如果 worker 在线但恰好漏收了 pubsub 消息
- pending 指令只在启动或重连时消费,就可能造成:
- 页面显示“已启动”
- 但 worker 实际没有进入新的执行流
当前已完成最小修复:
- 每条控制消息带 `request_id`
- worker 心跳会主动补偿消费 pending 指令
- worker 真正收到并处理后,会按 `request_id` 清理 pending
这一步现在已经不再是“待部署假设”,而是已被线上日志确认生效:
- `mainland-worker-01` 已从 pending 指令恢复执行
- `mainland-controller-01` 在修正 Redis 环境后,也已重新接受并执行 `start_detection`
## 当前结论
当前结论要收敛成一句话:
- 接管链路已基本完成
- 同步链路已至少成功贯通一次
- 当前主阻塞仍是检测执行面没有恢复到“持续产出”
- 但代码级控制链缺口已经闭合
- 当前唯一剩余现场阻塞可以收紧为:
- `mainland-controller-01` 代理池可用性为 `0`
- worker 侧时光机异常仍是次级噪音,不应继续放大
## 下一步唯一主批次
唯一主批次维持为:`J2-检测执行停滞收口批`
本批次唯一目标:
- 保持当前不扩功能
- 只围绕 controller 代理池可用性为 `0` 做收口
- 继续观察修正后的 controller 是否开始产出 domain 级结果
- 若仍无结果增长,则只给出代理层最小补救路径
## 候选批次
### Candidate J3
名称:检测执行恢复验证批
进入条件:
- `J2` 明确根因后
- 代理或外部站点依赖恢复
- 再观察 `domain_*` 是否重新增长
### Candidate J4
名称:上线签收证据批
进入条件:
- `J3` 确认检测重新持续产出
- `go-live-summary` 只剩历史 attention
## 暂停项
继续暂停:
- 新页面
- 新模块
- 控制面增强
- 发布动作
- 与检测执行停滞无关的工作
## 下一轮唯一动作
下一轮唯一应该继续做的事情:
- 只做 controller 代理收口:
- 继续复查 controller `domaincheck-worker` 日志
- 观察是否从 `当前无可用代理` 转为有可用代理
- 继续复查 `/api/v1/detect/job/active`
- 继续复查 `/api/v1/runtime/sync-summary`
- 继续复查 recent domain events 是否出现 controller / 新 completed
- 唯一判断问题是:
- controller 代理池恢复后completed 是否开始继续增长
- 是否仍是 `近窗吞吐 0`
- 是否仍是 `controller 可用代理数 0`
- 代理恢复后 `domain_*` 是否重新增长

View File

@@ -0,0 +1 @@
680339

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"base_url":"http://127.0.0.1:8100","generated_at":"2026-04-19 01:29:38","go_live_status":"attention","publish_ready":false,"publish_status":"attention","publish_status_label":"可发布但建议先复核","publish_summary":"当前没有硬阻断,但仍有上线前关注项,建议先完成复核再正式发版。","stack_status":"attention","contracts_ready":true,"contracts_total":11,"launchpad_status":"attention","launchpad_status_label":"待补执行面","launchpad_recommended_action_code":"fix_managed_nodes","launchpad_recommended_target_node_code":"","launchpad_recommended_recovery_label":"","launchpad_recommended_recovery_summary":"来自 overview.recommendation.primary_action_code","launchpad_onboarding_bootstrap_pending_nodes":0,"launchpad_onboarding_acceptance_ready_nodes":0,"route_surface_complete":true,"route_surface_missing_keys":[],"route_surface_declares_bootstrap_plan":true,"runtime_schema_stale":false,"repository_capabilities":{"supports_install_command_block":true,"supports_multi_layout_bootstrap":true},"managed_enabled":3,"remote_access_ready":3,"queue_dead_letter_nodes":0,"activity_start_delivery_issue_total":0,"participating_nodes_total":3,"log_sync_enabled":true,"log_sync_state":"full_capture","log_sync_mode":"full","log_sync_covered_nodes":3,"log_sync_missing_node_codes":[],"next_step_action_code":"focus_playbook_run","next_step_reason":"来自 overview.recommendation.primary_action_code","operator_lane":"ops_jobs","operator_title":"按总检默认下一步继续处理","operator_primary_command_key":"focus_playbook_run","publish_blocking_reasons":[],"publish_warnings":["stack_diagnosis=attention","release_launchpad=attention"],"blocking_reasons":[],"warnings":["stack_diagnosis=attention","release_launchpad=attention"],"recommended_commands":{"stack_summary":"bash domain-api/deploy/multi-region/check_ops_center_stack.sh http://127.0.0.1:8100 summary","contracts":"bash domain-api/deploy/multi-region/check_ops_contracts.sh http://127.0.0.1:8100","ops_plane":"bash domain-api/deploy/multi-region/check_ops_plane.sh http://127.0.0.1:8100","release_hub":"bash domain-api/deploy/multi-region/check_release_hub.sh http://127.0.0.1:8100","inspection":"bash domain-api/deploy/multi-region/check_ops_inspection.sh http://127.0.0.1:8100","overview":"bash domain-api/deploy/multi-region/drive_ops_center.sh overview http://127.0.0.1:8100","go_live_recover":"bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover http://127.0.0.1:8100","doctor_export":"bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-export /tmp/domaincheck-go-live http://127.0.0.1:8100","next_step":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 focus_playbook_run","log_sync_logs":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 open_worker_logs_participating","log_sync_inspection":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 run_inspection_participating"},"source_refs":{"stack_diagnosis_contract_key":"ops_stack_diagnosis_contract","contracts_registry_version":"2026-04-18","runtime_build_commit_sha":"246838ae4c07","release_focus_ref":{"kind":"release_hub","release_id":2,"release_version":"domaincheck_release_20260418_013833","channel":"stable","rollout_id":0,"rollout_code":"","section":"release_launchpad"}}},"detail_code":null}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"node_code":"overseas-control-01","available":true,"status":"full_capture","status_label":"全量观察","status_type":"success","summary":"节点当前正在参与检测,已保留 1 条现场日志样本。","log_sync_enabled":true,"mode":"full","mode_label":"全量回传","records_total":0,"records_visible":0,"records_truncated":false,"records":[],"latest_record":{},"source_summary":{"node_code":"overseas-control-01","line_count":1,"key_line_count":0,"full_line_count":1,"last_at":"2026-04-19 01:20:35","last_line":"[2026-04-19 01:20:35] [overseas-control-01] 2026-04-19 01:00:18.866 | INFO | __main__:start_detection:2575 - 开始执行域名检测任务"},"missing_reason_code":"","missing_reason":"","node":{"node_code":"overseas-control-01","region":"overseas","role":"control","status":"busy","current_load":25,"last_heartbeat_at":"2026-04-19 01:29:45"},"participation":{"detect_participating":true,"participation_state":"running","participation_label":"执行中","participation_reason":"当前正在执行 4 项检测任务。","participation_bucket":"dispatch_active","participation_bucket_label":"执行/已领","is_dispatch_active":true},"contract_navigation":{"detail_endpoint_pattern":"/api/v1/ops/contracts/{contract_key}","primary_contract_key":"ops_observability_contract","contract_keys":["ops_observability_contract","ops_stack_diagnosis_contract"],"contracts":[{"key":"ops_observability_contract","title":"Ops Observability Contract","status":"active","version":"v1","summary":"冻结 execution scene / inspection overview / activity stream / delivery queue 的正式观察面 contract。","primary_endpoint":"/api/v1/ops/overview","schema_doc_path":"docs/schemas/ops_observability_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_observability_contract","discovery_endpoints":["/api/v1/ops/overview","/api/v1/ops/inspection-overview","/api/v1/ops/activity-stream","/api/v1/ops/nodes/{node_code}/scene-log","/api/v1/ops/nodes/{node_code}/delivery-queue","/api/v1/ops/nodes/{node_code}/delivery-queue/records","/api/v1/ops/nodes/{node_code}/delivery-queue/flush","/api/v1/ops/nodes/{node_code}/delivery-queue/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/discard"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","ops_driver_contract","ops_playbook_contract","ops_stack_diagnosis_contract"]},{"key":"ops_stack_diagnosis_contract","title":"Ops Stack Diagnosis Contract","status":"active","version":"v1","summary":"冻结海外单脑总检入口的统一诊断 contract供页面、CLI、Codex、按钮共享同一份第一现场判断。","primary_endpoint":"/api/v1/ops/stack-diagnosis","schema_doc_path":"docs/schemas/ops_stack_diagnosis_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_stack_diagnosis_contract","discovery_endpoints":["/api/v1/ops/go-live-summary","/api/v1/ops/stack-diagnosis","/api/v1/ops/contracts","/api/v1/ops/link-snapshot","/api/v1/ops/overview","/api/v1/ops/nodes","/api/v1/ops/releases/launchpad","/api/v1/ops/playbook-runs","/api/v1/ops/activity-stream"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","release_hub_contract","ops_driver_contract","ops_playbook_contract","ops_observability_contract"]}]}},"detail_code":null}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
CYCLES="1"
GO_LIVE_STATUS="attention"
PUBLISH_READY="false"
LOG_SYNC_STATE="full_capture"
LOG_SYNC_MISSING_NODE_CODES=""
STACK_STATUS="attention"
ISSUE_TOTAL="1"
BLOCKING_ISSUE_TOTAL="0"
ISSUE_CODES="playbook_runs_need_attention"
LAUNCHPAD_STATUS="blocked"
LAUNCHPAD_RECOMMENDED_ACTION="run_acceptance"
PROBLEM_RUNS_TOTAL="0"
PROBLEM_RUN_CODE=""
SCENE_STATUS="full_capture"
SCENE_LINE_COUNT="1"
GENERATED_AT="2026-04-19 01:29:38"

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"base_url":"http://127.0.0.1:8100","generated_at":"2026-04-19 02:29:55","go_live_status":"attention","publish_ready":false,"publish_status":"attention","publish_status_label":"可发布但建议先复核","publish_summary":"当前没有硬阻断,但仍有上线前关注项,建议先完成复核再正式发版。","stack_status":"attention","contracts_ready":true,"contracts_total":11,"launchpad_status":"attention","launchpad_status_label":"待补执行面","launchpad_recommended_action_code":"fix_managed_nodes","launchpad_recommended_target_node_code":"","launchpad_recommended_recovery_label":"","launchpad_recommended_recovery_summary":"来自 overview.recommendation.primary_action_code","launchpad_onboarding_bootstrap_pending_nodes":0,"launchpad_onboarding_acceptance_ready_nodes":0,"route_surface_complete":true,"route_surface_missing_keys":[],"route_surface_declares_bootstrap_plan":true,"runtime_schema_stale":false,"repository_capabilities":{"supports_install_command_block":true,"supports_multi_layout_bootstrap":true},"managed_enabled":3,"remote_access_ready":3,"queue_dead_letter_nodes":0,"activity_start_delivery_issue_total":0,"participating_nodes_total":3,"log_sync_enabled":true,"log_sync_state":"full_capture","log_sync_mode":"full","log_sync_covered_nodes":3,"log_sync_missing_node_codes":[],"next_step_action_code":"focus_playbook_run","next_step_reason":"来自 overview.recommendation.primary_action_code","operator_lane":"ops_jobs","operator_title":"按总检默认下一步继续处理","operator_primary_command_key":"focus_playbook_run","publish_blocking_reasons":[],"publish_warnings":["stack_diagnosis=attention","release_launchpad=attention"],"blocking_reasons":[],"warnings":["stack_diagnosis=attention","release_launchpad=attention"],"recommended_commands":{"stack_summary":"bash domain-api/deploy/multi-region/check_ops_center_stack.sh http://127.0.0.1:8100 summary","contracts":"bash domain-api/deploy/multi-region/check_ops_contracts.sh http://127.0.0.1:8100","ops_plane":"bash domain-api/deploy/multi-region/check_ops_plane.sh http://127.0.0.1:8100","release_hub":"bash domain-api/deploy/multi-region/check_release_hub.sh http://127.0.0.1:8100","inspection":"bash domain-api/deploy/multi-region/check_ops_inspection.sh http://127.0.0.1:8100","overview":"bash domain-api/deploy/multi-region/drive_ops_center.sh overview http://127.0.0.1:8100","go_live_recover":"bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover http://127.0.0.1:8100","doctor_export":"bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-export /tmp/domaincheck-go-live http://127.0.0.1:8100","next_step":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 focus_playbook_run","log_sync_logs":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 open_worker_logs_participating","log_sync_inspection":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 run_inspection_participating"},"source_refs":{"stack_diagnosis_contract_key":"ops_stack_diagnosis_contract","contracts_registry_version":"2026-04-18","runtime_build_commit_sha":"246838ae4c07","release_focus_ref":{"kind":"release_hub","release_id":2,"release_version":"domaincheck_release_20260418_013833","channel":"stable","rollout_id":0,"rollout_code":"","section":"release_launchpad"}}},"detail_code":null}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"node_code":"overseas-control-01","available":true,"status":"full_capture","status_label":"全量观察","status_type":"success","summary":"节点当前正在参与检测,已保留 1 条现场日志样本。","log_sync_enabled":true,"mode":"full","mode_label":"全量回传","records_total":0,"records_visible":0,"records_truncated":false,"records":[],"latest_record":{},"source_summary":{"node_code":"overseas-control-01","line_count":1,"key_line_count":0,"full_line_count":1,"last_at":"2026-04-19 01:20:35","last_line":"[2026-04-19 01:20:35] [overseas-control-01] 2026-04-19 01:00:18.866 | INFO | __main__:start_detection:2575 - 开始执行域名检测任务"},"missing_reason_code":"","missing_reason":"","node":{"node_code":"overseas-control-01","region":"overseas","role":"control","status":"busy","current_load":25,"last_heartbeat_at":"2026-04-19 02:30:02"},"participation":{"detect_participating":true,"participation_state":"running","participation_label":"执行中","participation_reason":"当前正在执行 4 项检测任务。","participation_bucket":"dispatch_active","participation_bucket_label":"执行/已领","is_dispatch_active":true},"contract_navigation":{"detail_endpoint_pattern":"/api/v1/ops/contracts/{contract_key}","primary_contract_key":"ops_observability_contract","contract_keys":["ops_observability_contract","ops_stack_diagnosis_contract"],"contracts":[{"key":"ops_observability_contract","title":"Ops Observability Contract","status":"active","version":"v1","summary":"冻结 execution scene / inspection overview / activity stream / delivery queue 的正式观察面 contract。","primary_endpoint":"/api/v1/ops/overview","schema_doc_path":"docs/schemas/ops_observability_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_observability_contract","discovery_endpoints":["/api/v1/ops/overview","/api/v1/ops/inspection-overview","/api/v1/ops/activity-stream","/api/v1/ops/nodes/{node_code}/scene-log","/api/v1/ops/nodes/{node_code}/delivery-queue","/api/v1/ops/nodes/{node_code}/delivery-queue/records","/api/v1/ops/nodes/{node_code}/delivery-queue/flush","/api/v1/ops/nodes/{node_code}/delivery-queue/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/discard"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","ops_driver_contract","ops_playbook_contract","ops_stack_diagnosis_contract"]},{"key":"ops_stack_diagnosis_contract","title":"Ops Stack Diagnosis Contract","status":"active","version":"v1","summary":"冻结海外单脑总检入口的统一诊断 contract供页面、CLI、Codex、按钮共享同一份第一现场判断。","primary_endpoint":"/api/v1/ops/stack-diagnosis","schema_doc_path":"docs/schemas/ops_stack_diagnosis_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_stack_diagnosis_contract","discovery_endpoints":["/api/v1/ops/go-live-summary","/api/v1/ops/stack-diagnosis","/api/v1/ops/contracts","/api/v1/ops/link-snapshot","/api/v1/ops/overview","/api/v1/ops/nodes","/api/v1/ops/releases/launchpad","/api/v1/ops/playbook-runs","/api/v1/ops/activity-stream"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","release_hub_contract","ops_driver_contract","ops_playbook_contract","ops_observability_contract"]}]}},"detail_code":null}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
CYCLES="2"
GO_LIVE_STATUS="attention"
PUBLISH_READY="false"
LOG_SYNC_STATE="full_capture"
LOG_SYNC_MISSING_NODE_CODES=""
STACK_STATUS="attention"
ISSUE_TOTAL="1"
BLOCKING_ISSUE_TOTAL="0"
ISSUE_CODES="playbook_runs_need_attention"
LAUNCHPAD_STATUS="blocked"
LAUNCHPAD_RECOMMENDED_ACTION="run_acceptance"
PROBLEM_RUNS_TOTAL="0"
PROBLEM_RUN_CODE=""
SCENE_STATUS="full_capture"
SCENE_LINE_COUNT="1"
GENERATED_AT="2026-04-19 02:29:55"

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"base_url":"http://127.0.0.1:8100","generated_at":"2026-04-19 03:30:12","go_live_status":"attention","publish_ready":false,"publish_status":"attention","publish_status_label":"可发布但建议先复核","publish_summary":"当前没有硬阻断,但仍有上线前关注项,建议先完成复核再正式发版。","stack_status":"attention","contracts_ready":true,"contracts_total":11,"launchpad_status":"attention","launchpad_status_label":"待补执行面","launchpad_recommended_action_code":"fix_managed_nodes","launchpad_recommended_target_node_code":"","launchpad_recommended_recovery_label":"","launchpad_recommended_recovery_summary":"来自 overview.recommendation.primary_action_code","launchpad_onboarding_bootstrap_pending_nodes":0,"launchpad_onboarding_acceptance_ready_nodes":0,"route_surface_complete":true,"route_surface_missing_keys":[],"route_surface_declares_bootstrap_plan":true,"runtime_schema_stale":false,"repository_capabilities":{"supports_install_command_block":true,"supports_multi_layout_bootstrap":true},"managed_enabled":3,"remote_access_ready":3,"queue_dead_letter_nodes":0,"activity_start_delivery_issue_total":0,"participating_nodes_total":3,"log_sync_enabled":true,"log_sync_state":"partial_coverage","log_sync_mode":"full","log_sync_covered_nodes":2,"log_sync_missing_node_codes":["overseas-control-01"],"next_step_action_code":"focus_playbook_run","next_step_reason":"来自 overview.recommendation.primary_action_code","operator_lane":"ops_jobs","operator_title":"按总检默认下一步继续处理","operator_primary_command_key":"focus_playbook_run","publish_blocking_reasons":[],"publish_warnings":["stack_diagnosis=attention","release_launchpad=attention","log_sync_partial=2/3"],"blocking_reasons":[],"warnings":["stack_diagnosis=attention","release_launchpad=attention","log_sync_partial=2/3"],"recommended_commands":{"stack_summary":"bash domain-api/deploy/multi-region/check_ops_center_stack.sh http://127.0.0.1:8100 summary","contracts":"bash domain-api/deploy/multi-region/check_ops_contracts.sh http://127.0.0.1:8100","ops_plane":"bash domain-api/deploy/multi-region/check_ops_plane.sh http://127.0.0.1:8100","release_hub":"bash domain-api/deploy/multi-region/check_release_hub.sh http://127.0.0.1:8100","inspection":"bash domain-api/deploy/multi-region/check_ops_inspection.sh http://127.0.0.1:8100","overview":"bash domain-api/deploy/multi-region/drive_ops_center.sh overview http://127.0.0.1:8100","go_live_recover":"bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover http://127.0.0.1:8100","doctor_export":"bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-export /tmp/domaincheck-go-live http://127.0.0.1:8100","next_step":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 focus_playbook_run","log_sync_logs":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 open_worker_logs_participating","log_sync_inspection":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 run_inspection_participating"},"source_refs":{"stack_diagnosis_contract_key":"ops_stack_diagnosis_contract","contracts_registry_version":"2026-04-18","runtime_build_commit_sha":"246838ae4c07","release_focus_ref":{"kind":"release_hub","release_id":2,"release_version":"domaincheck_release_20260418_013833","channel":"stable","rollout_id":0,"rollout_code":"","section":"release_launchpad"}}},"detail_code":null}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"node_code":"overseas-control-01","available":true,"status":"missing_sample","status_label":"缺少样本","status_type":"warning","summary":"当前还没有收到该参与节点的远端日志样本。","log_sync_enabled":true,"mode":"full","mode_label":"全量回传","records_total":0,"records_visible":0,"records_truncated":false,"records":[],"latest_record":{},"source_summary":{"node_code":"overseas-control-01","line_count":0,"key_line_count":0,"full_line_count":0,"last_at":"","last_line":""},"missing_reason_code":"no_sample","missing_reason":"当前还没有收到该参与节点的远端日志样本。","node":{"node_code":"overseas-control-01","region":"overseas","role":"control","status":"busy","current_load":25,"last_heartbeat_at":"2026-04-19 03:30:19"},"participation":{"detect_participating":true,"participation_state":"running","participation_label":"执行中","participation_reason":"当前正在执行 4 项检测任务。","participation_bucket":"dispatch_active","participation_bucket_label":"执行/已领","is_dispatch_active":true},"contract_navigation":{"detail_endpoint_pattern":"/api/v1/ops/contracts/{contract_key}","primary_contract_key":"ops_observability_contract","contract_keys":["ops_observability_contract","ops_stack_diagnosis_contract"],"contracts":[{"key":"ops_observability_contract","title":"Ops Observability Contract","status":"active","version":"v1","summary":"冻结 execution scene / inspection overview / activity stream / delivery queue 的正式观察面 contract。","primary_endpoint":"/api/v1/ops/overview","schema_doc_path":"docs/schemas/ops_observability_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_observability_contract","discovery_endpoints":["/api/v1/ops/overview","/api/v1/ops/inspection-overview","/api/v1/ops/activity-stream","/api/v1/ops/nodes/{node_code}/scene-log","/api/v1/ops/nodes/{node_code}/delivery-queue","/api/v1/ops/nodes/{node_code}/delivery-queue/records","/api/v1/ops/nodes/{node_code}/delivery-queue/flush","/api/v1/ops/nodes/{node_code}/delivery-queue/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/discard"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","ops_driver_contract","ops_playbook_contract","ops_stack_diagnosis_contract"]},{"key":"ops_stack_diagnosis_contract","title":"Ops Stack Diagnosis Contract","status":"active","version":"v1","summary":"冻结海外单脑总检入口的统一诊断 contract供页面、CLI、Codex、按钮共享同一份第一现场判断。","primary_endpoint":"/api/v1/ops/stack-diagnosis","schema_doc_path":"docs/schemas/ops_stack_diagnosis_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_stack_diagnosis_contract","discovery_endpoints":["/api/v1/ops/go-live-summary","/api/v1/ops/stack-diagnosis","/api/v1/ops/contracts","/api/v1/ops/link-snapshot","/api/v1/ops/overview","/api/v1/ops/nodes","/api/v1/ops/releases/launchpad","/api/v1/ops/playbook-runs","/api/v1/ops/activity-stream"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","release_hub_contract","ops_driver_contract","ops_playbook_contract","ops_observability_contract"]}]}},"detail_code":null}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
CYCLES="3"
GO_LIVE_STATUS="attention"
PUBLISH_READY="false"
LOG_SYNC_STATE="partial_coverage"
LOG_SYNC_MISSING_NODE_CODES="overseas-control-01"
STACK_STATUS="attention"
ISSUE_TOTAL="2"
BLOCKING_ISSUE_TOTAL="0"
ISSUE_CODES="remote_log_sync_waiting_sample,playbook_runs_need_attention"
LAUNCHPAD_STATUS="blocked"
LAUNCHPAD_RECOMMENDED_ACTION="run_acceptance"
PROBLEM_RUNS_TOTAL="0"
PROBLEM_RUN_CODE=""
SCENE_STATUS="missing_sample"
SCENE_LINE_COUNT="0"
GENERATED_AT="2026-04-19 03:30:12"

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"base_url":"http://127.0.0.1:8100","generated_at":"2026-04-19 03:31:26","go_live_status":"attention","publish_ready":false,"publish_status":"attention","publish_status_label":"可发布但建议先复核","publish_summary":"当前没有硬阻断,但仍有上线前关注项,建议先完成复核再正式发版。","stack_status":"attention","contracts_ready":true,"contracts_total":11,"launchpad_status":"attention","launchpad_status_label":"待补执行面","launchpad_recommended_action_code":"fix_managed_nodes","launchpad_recommended_target_node_code":"","launchpad_recommended_recovery_label":"","launchpad_recommended_recovery_summary":"来自 overview.recommendation.primary_action_code","launchpad_onboarding_bootstrap_pending_nodes":0,"launchpad_onboarding_acceptance_ready_nodes":0,"route_surface_complete":true,"route_surface_missing_keys":[],"route_surface_declares_bootstrap_plan":true,"runtime_schema_stale":false,"repository_capabilities":{"supports_install_command_block":true,"supports_multi_layout_bootstrap":true},"managed_enabled":3,"remote_access_ready":3,"queue_dead_letter_nodes":0,"activity_start_delivery_issue_total":0,"participating_nodes_total":3,"log_sync_enabled":true,"log_sync_state":"full_capture","log_sync_mode":"full","log_sync_covered_nodes":3,"log_sync_missing_node_codes":[],"next_step_action_code":"focus_playbook_run","next_step_reason":"来自 overview.recommendation.primary_action_code","operator_lane":"ops_jobs","operator_title":"按总检默认下一步继续处理","operator_primary_command_key":"focus_playbook_run","publish_blocking_reasons":[],"publish_warnings":["stack_diagnosis=attention","release_launchpad=attention"],"blocking_reasons":[],"warnings":["stack_diagnosis=attention","release_launchpad=attention"],"recommended_commands":{"stack_summary":"bash domain-api/deploy/multi-region/check_ops_center_stack.sh http://127.0.0.1:8100 summary","contracts":"bash domain-api/deploy/multi-region/check_ops_contracts.sh http://127.0.0.1:8100","ops_plane":"bash domain-api/deploy/multi-region/check_ops_plane.sh http://127.0.0.1:8100","release_hub":"bash domain-api/deploy/multi-region/check_release_hub.sh http://127.0.0.1:8100","inspection":"bash domain-api/deploy/multi-region/check_ops_inspection.sh http://127.0.0.1:8100","overview":"bash domain-api/deploy/multi-region/drive_ops_center.sh overview http://127.0.0.1:8100","go_live_recover":"bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover http://127.0.0.1:8100","doctor_export":"bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-export /tmp/domaincheck-go-live http://127.0.0.1:8100","next_step":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 focus_playbook_run","log_sync_logs":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 open_worker_logs_participating","log_sync_inspection":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 run_inspection_participating"},"source_refs":{"stack_diagnosis_contract_key":"ops_stack_diagnosis_contract","contracts_registry_version":"2026-04-18","runtime_build_commit_sha":"246838ae4c07","release_focus_ref":{"kind":"release_hub","release_id":2,"release_version":"domaincheck_release_20260418_013833","channel":"stable","rollout_id":0,"rollout_code":"","section":"release_launchpad"}}},"detail_code":null}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"node_code":"overseas-control-01","available":true,"status":"full_capture","status_label":"全量观察","status_type":"success","summary":"节点当前正在参与检测,已保留 3 条现场日志样本。","log_sync_enabled":true,"mode":"full","mode_label":"全量回传","records_total":0,"records_visible":0,"records_truncated":false,"records":[],"latest_record":{},"source_summary":{"node_code":"overseas-control-01","line_count":3,"key_line_count":0,"full_line_count":3,"last_at":"2026-04-19 03:30:30","last_line":"[2026-04-19 03:30:30] [overseas-control-01] 2026-04-19 01:59:40.686 | WARNING | __main__:start_detection_async:1073 - 收到启动检测指令,但检测任务已在运行,忽略重复启动"},"missing_reason_code":"","missing_reason":"","node":{"node_code":"overseas-control-01","region":"overseas","role":"control","status":"busy","current_load":25,"last_heartbeat_at":"2026-04-19 03:31:33"},"participation":{"detect_participating":true,"participation_state":"running","participation_label":"执行中","participation_reason":"当前正在执行 4 项检测任务。","participation_bucket":"dispatch_active","participation_bucket_label":"执行/已领","is_dispatch_active":true},"contract_navigation":{"detail_endpoint_pattern":"/api/v1/ops/contracts/{contract_key}","primary_contract_key":"ops_observability_contract","contract_keys":["ops_observability_contract","ops_stack_diagnosis_contract"],"contracts":[{"key":"ops_observability_contract","title":"Ops Observability Contract","status":"active","version":"v1","summary":"冻结 execution scene / inspection overview / activity stream / delivery queue 的正式观察面 contract。","primary_endpoint":"/api/v1/ops/overview","schema_doc_path":"docs/schemas/ops_observability_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_observability_contract","discovery_endpoints":["/api/v1/ops/overview","/api/v1/ops/inspection-overview","/api/v1/ops/activity-stream","/api/v1/ops/nodes/{node_code}/scene-log","/api/v1/ops/nodes/{node_code}/delivery-queue","/api/v1/ops/nodes/{node_code}/delivery-queue/records","/api/v1/ops/nodes/{node_code}/delivery-queue/flush","/api/v1/ops/nodes/{node_code}/delivery-queue/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/discard"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","ops_driver_contract","ops_playbook_contract","ops_stack_diagnosis_contract"]},{"key":"ops_stack_diagnosis_contract","title":"Ops Stack Diagnosis Contract","status":"active","version":"v1","summary":"冻结海外单脑总检入口的统一诊断 contract供页面、CLI、Codex、按钮共享同一份第一现场判断。","primary_endpoint":"/api/v1/ops/stack-diagnosis","schema_doc_path":"docs/schemas/ops_stack_diagnosis_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_stack_diagnosis_contract","discovery_endpoints":["/api/v1/ops/go-live-summary","/api/v1/ops/stack-diagnosis","/api/v1/ops/contracts","/api/v1/ops/link-snapshot","/api/v1/ops/overview","/api/v1/ops/nodes","/api/v1/ops/releases/launchpad","/api/v1/ops/playbook-runs","/api/v1/ops/activity-stream"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","release_hub_contract","ops_driver_contract","ops_playbook_contract","ops_observability_contract"]}]}},"detail_code":null}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
CYCLES="4"
GO_LIVE_STATUS="attention"
PUBLISH_READY="false"
LOG_SYNC_STATE="full_capture"
LOG_SYNC_MISSING_NODE_CODES=""
STACK_STATUS="attention"
ISSUE_TOTAL="1"
BLOCKING_ISSUE_TOTAL="0"
ISSUE_CODES="playbook_runs_need_attention"
LAUNCHPAD_STATUS="blocked"
LAUNCHPAD_RECOMMENDED_ACTION="run_acceptance"
PROBLEM_RUNS_TOTAL="0"
PROBLEM_RUN_CODE=""
SCENE_STATUS="full_capture"
SCENE_LINE_COUNT="3"
GENERATED_AT="2026-04-19 03:31:26"

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"base_url":"http://127.0.0.1:8100","generated_at":"2026-04-19 04:31:45","go_live_status":"attention","publish_ready":false,"publish_status":"attention","publish_status_label":"可发布但建议先复核","publish_summary":"当前没有硬阻断,但仍有上线前关注项,建议先完成复核再正式发版。","stack_status":"attention","contracts_ready":true,"contracts_total":11,"launchpad_status":"attention","launchpad_status_label":"待补执行面","launchpad_recommended_action_code":"fix_managed_nodes","launchpad_recommended_target_node_code":"","launchpad_recommended_recovery_label":"","launchpad_recommended_recovery_summary":"来自 overview.recommendation.primary_action_code","launchpad_onboarding_bootstrap_pending_nodes":0,"launchpad_onboarding_acceptance_ready_nodes":0,"route_surface_complete":true,"route_surface_missing_keys":[],"route_surface_declares_bootstrap_plan":true,"runtime_schema_stale":false,"repository_capabilities":{"supports_install_command_block":true,"supports_multi_layout_bootstrap":true},"managed_enabled":3,"remote_access_ready":3,"queue_dead_letter_nodes":0,"activity_start_delivery_issue_total":0,"participating_nodes_total":3,"log_sync_enabled":true,"log_sync_state":"partial_coverage","log_sync_mode":"full","log_sync_covered_nodes":2,"log_sync_missing_node_codes":["overseas-control-01"],"next_step_action_code":"focus_playbook_run","next_step_reason":"来自 overview.recommendation.primary_action_code","operator_lane":"ops_jobs","operator_title":"按总检默认下一步继续处理","operator_primary_command_key":"focus_playbook_run","publish_blocking_reasons":[],"publish_warnings":["stack_diagnosis=attention","release_launchpad=attention","log_sync_partial=2/3"],"blocking_reasons":[],"warnings":["stack_diagnosis=attention","release_launchpad=attention","log_sync_partial=2/3"],"recommended_commands":{"stack_summary":"bash domain-api/deploy/multi-region/check_ops_center_stack.sh http://127.0.0.1:8100 summary","contracts":"bash domain-api/deploy/multi-region/check_ops_contracts.sh http://127.0.0.1:8100","ops_plane":"bash domain-api/deploy/multi-region/check_ops_plane.sh http://127.0.0.1:8100","release_hub":"bash domain-api/deploy/multi-region/check_release_hub.sh http://127.0.0.1:8100","inspection":"bash domain-api/deploy/multi-region/check_ops_inspection.sh http://127.0.0.1:8100","overview":"bash domain-api/deploy/multi-region/drive_ops_center.sh overview http://127.0.0.1:8100","go_live_recover":"bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover http://127.0.0.1:8100","doctor_export":"bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-export /tmp/domaincheck-go-live http://127.0.0.1:8100","next_step":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 focus_playbook_run","log_sync_logs":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 open_worker_logs_participating","log_sync_inspection":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 run_inspection_participating"},"source_refs":{"stack_diagnosis_contract_key":"ops_stack_diagnosis_contract","contracts_registry_version":"2026-04-18","runtime_build_commit_sha":"246838ae4c07","release_focus_ref":{"kind":"release_hub","release_id":2,"release_version":"domaincheck_release_20260418_013833","channel":"stable","rollout_id":0,"rollout_code":"","section":"release_launchpad"}}},"detail_code":null}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"node_code":"overseas-control-01","available":true,"status":"missing_sample","status_label":"缺少样本","status_type":"warning","summary":"当前还没有收到该参与节点的远端日志样本。","log_sync_enabled":true,"mode":"full","mode_label":"全量回传","records_total":0,"records_visible":0,"records_truncated":false,"records":[],"latest_record":{},"source_summary":{"node_code":"overseas-control-01","line_count":0,"key_line_count":0,"full_line_count":0,"last_at":"","last_line":""},"missing_reason_code":"no_sample","missing_reason":"当前还没有收到该参与节点的远端日志样本。","node":{"node_code":"overseas-control-01","region":"overseas","role":"control","status":"busy","current_load":25,"last_heartbeat_at":"2026-04-19 04:31:52"},"participation":{"detect_participating":true,"participation_state":"running","participation_label":"执行中","participation_reason":"当前正在执行 4 项检测任务。","participation_bucket":"dispatch_active","participation_bucket_label":"执行/已领","is_dispatch_active":true},"contract_navigation":{"detail_endpoint_pattern":"/api/v1/ops/contracts/{contract_key}","primary_contract_key":"ops_observability_contract","contract_keys":["ops_observability_contract","ops_stack_diagnosis_contract"],"contracts":[{"key":"ops_observability_contract","title":"Ops Observability Contract","status":"active","version":"v1","summary":"冻结 execution scene / inspection overview / activity stream / delivery queue 的正式观察面 contract。","primary_endpoint":"/api/v1/ops/overview","schema_doc_path":"docs/schemas/ops_observability_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_observability_contract","discovery_endpoints":["/api/v1/ops/overview","/api/v1/ops/inspection-overview","/api/v1/ops/activity-stream","/api/v1/ops/nodes/{node_code}/scene-log","/api/v1/ops/nodes/{node_code}/delivery-queue","/api/v1/ops/nodes/{node_code}/delivery-queue/records","/api/v1/ops/nodes/{node_code}/delivery-queue/flush","/api/v1/ops/nodes/{node_code}/delivery-queue/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/replay","/api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/discard"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","ops_driver_contract","ops_playbook_contract","ops_stack_diagnosis_contract"]},{"key":"ops_stack_diagnosis_contract","title":"Ops Stack Diagnosis Contract","status":"active","version":"v1","summary":"冻结海外单脑总检入口的统一诊断 contract供页面、CLI、Codex、按钮共享同一份第一现场判断。","primary_endpoint":"/api/v1/ops/stack-diagnosis","schema_doc_path":"docs/schemas/ops_stack_diagnosis_contract.md","detail_endpoint":"/api/v1/ops/contracts/ops_stack_diagnosis_contract","discovery_endpoints":["/api/v1/ops/go-live-summary","/api/v1/ops/stack-diagnosis","/api/v1/ops/contracts","/api/v1/ops/link-snapshot","/api/v1/ops/overview","/api/v1/ops/nodes","/api/v1/ops/releases/launchpad","/api/v1/ops/playbook-runs","/api/v1/ops/activity-stream"],"related_contract_keys":["ops_job_contract","ops_agent_protocol","release_hub_contract","ops_driver_contract","ops_playbook_contract","ops_observability_contract"]}]}},"detail_code":null}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,16 @@
CYCLES="5"
GO_LIVE_STATUS="attention"
PUBLISH_READY="false"
LOG_SYNC_STATE="partial_coverage"
LOG_SYNC_MISSING_NODE_CODES="overseas-control-01"
STACK_STATUS="attention"
ISSUE_TOTAL="2"
BLOCKING_ISSUE_TOTAL="0"
ISSUE_CODES="remote_log_sync_waiting_sample,playbook_runs_need_attention"
LAUNCHPAD_STATUS="blocked"
LAUNCHPAD_RECOMMENDED_ACTION="run_acceptance"
PROBLEM_RUNS_TOTAL="0"
PROBLEM_RUN_CODE=""
SCENE_STATUS="missing_sample"
SCENE_LINE_COUNT="0"
GENERATED_AT="2026-04-19 04:31:45"

View File

@@ -0,0 +1,16 @@
CYCLES="6"
GO_LIVE_STATUS=""
PUBLISH_READY="false"
LOG_SYNC_STATE=""
LOG_SYNC_MISSING_NODE_CODES=""
STACK_STATUS=""
ISSUE_TOTAL="0"
BLOCKING_ISSUE_TOTAL="0"
ISSUE_CODES=""
LAUNCHPAD_STATUS=""
LAUNCHPAD_RECOMMENDED_ACTION=""
PROBLEM_RUNS_TOTAL="0"
PROBLEM_RUN_CODE=""
SCENE_STATUS=""
SCENE_LINE_COUNT="0"
GENERATED_AT=""

View File

@@ -0,0 +1,16 @@
CYCLES="7"
GO_LIVE_STATUS=""
PUBLISH_READY="false"
LOG_SYNC_STATE=""
LOG_SYNC_MISSING_NODE_CODES=""
STACK_STATUS=""
ISSUE_TOTAL="0"
BLOCKING_ISSUE_TOTAL="0"
ISSUE_CODES=""
LAUNCHPAD_STATUS=""
LAUNCHPAD_RECOMMENDED_ACTION=""
PROBLEM_RUNS_TOTAL="0"
PROBLEM_RUN_CODE=""
SCENE_STATUS=""
SCENE_LINE_COUNT="0"
GENERATED_AT=""

View File

@@ -0,0 +1 @@
{"code":0,"message":"ok","data":{"base_url":"http://127.0.0.1:8100","generated_at":"2026-04-19 04:34:28","go_live_status":"attention","publish_ready":false,"publish_status":"attention","publish_status_label":"可发布但建议先复核","publish_summary":"当前没有硬阻断,但仍有上线前关注项,建议先完成复核再正式发版。","stack_status":"attention","contracts_ready":true,"contracts_total":11,"launchpad_status":"attention","launchpad_status_label":"待补执行面","launchpad_recommended_action_code":"fix_managed_nodes","launchpad_recommended_target_node_code":"","launchpad_recommended_recovery_label":"","launchpad_recommended_recovery_summary":"来自 overview.recommendation.primary_action_code","launchpad_onboarding_bootstrap_pending_nodes":0,"launchpad_onboarding_acceptance_ready_nodes":0,"route_surface_complete":true,"route_surface_missing_keys":[],"route_surface_declares_bootstrap_plan":true,"runtime_schema_stale":false,"repository_capabilities":{"supports_install_command_block":true,"supports_multi_layout_bootstrap":true},"managed_enabled":3,"remote_access_ready":3,"queue_dead_letter_nodes":0,"activity_start_delivery_issue_total":0,"participating_nodes_total":1,"log_sync_enabled":true,"log_sync_state":"full_capture","log_sync_mode":"full","log_sync_covered_nodes":1,"log_sync_missing_node_codes":[],"next_step_action_code":"focus_playbook_run","next_step_reason":"来自 overview.recommendation.primary_action_code","operator_lane":"ops_jobs","operator_title":"按总检默认下一步继续处理","operator_primary_command_key":"focus_playbook_run","publish_blocking_reasons":[],"publish_warnings":["stack_diagnosis=attention","release_launchpad=attention"],"blocking_reasons":[],"warnings":["stack_diagnosis=attention","release_launchpad=attention"],"recommended_commands":{"stack_summary":"bash domain-api/deploy/multi-region/check_ops_center_stack.sh http://127.0.0.1:8100 summary","contracts":"bash domain-api/deploy/multi-region/check_ops_contracts.sh http://127.0.0.1:8100","ops_plane":"bash domain-api/deploy/multi-region/check_ops_plane.sh http://127.0.0.1:8100","release_hub":"bash domain-api/deploy/multi-region/check_release_hub.sh http://127.0.0.1:8100","inspection":"bash domain-api/deploy/multi-region/check_ops_inspection.sh http://127.0.0.1:8100","overview":"bash domain-api/deploy/multi-region/drive_ops_center.sh overview http://127.0.0.1:8100","go_live_recover":"bash domain-api/deploy/multi-region/drive_ops_center.sh go-live-recover http://127.0.0.1:8100","doctor_export":"bash domain-api/deploy/multi-region/drive_ops_center.sh doctor-export /tmp/domaincheck-go-live http://127.0.0.1:8100","next_step":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 focus_playbook_run","log_sync_logs":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 open_worker_logs_participating","log_sync_inspection":"bash domain-api/deploy/multi-region/drive_ops_center.sh driver-resolve http://127.0.0.1:8100 run_inspection_participating"},"source_refs":{"stack_diagnosis_contract_key":"ops_stack_diagnosis_contract","contracts_registry_version":"2026-04-18","runtime_build_commit_sha":"246838ae4c07","release_focus_ref":{"kind":"release_hub","release_id":2,"release_version":"domaincheck_release_20260418_013833","channel":"stable","rollout_id":0,"rollout_code":"","section":"release_launchpad"}}},"detail_code":null}

View File

@@ -0,0 +1,16 @@
CYCLES="8"
GO_LIVE_STATUS="attention"
PUBLISH_READY="false"
LOG_SYNC_STATE="full_capture"
LOG_SYNC_MISSING_NODE_CODES=""
STACK_STATUS=""
ISSUE_TOTAL="0"
BLOCKING_ISSUE_TOTAL="0"
ISSUE_CODES=""
LAUNCHPAD_STATUS=""
LAUNCHPAD_RECOMMENDED_ACTION=""
PROBLEM_RUNS_TOTAL="0"
PROBLEM_RUN_CODE=""
SCENE_STATUS=""
SCENE_LINE_COUNT="0"
GENERATED_AT="2026-04-19 04:34:28"

View File

@@ -0,0 +1,59 @@
# night_run_20260419_012929 初步分析
## 结论
- 夜跑不是完全空跑,`cycle_1``cycle_8` 期间持续执行了巡检、收口和日志回传恢复动作。
- 真正的中断点出现在 `2026-04-19 04:32:49``04:33:35`,本机 API `127.0.0.1:8100` 短时不可达,导致两轮自动动作直接失败。
- 最终停止原因是 `signoff_ready_candidate`,这是“候选可签收”型收口,不等同于“整轮全绿、无异常结束”。
## 关键时间点
- `2026-04-19 01:29:29 +0800`
- 夜跑启动。
- `cycle_1``cycle_5`
- 持续产出 `go_live.json``launchpad.json``playbook_runs.json``stack.json``scene_overseas_control_01.json``summary.env`
- `2026-04-19 04:32:04 +0800`
- `run_inspection_participating` 成功创建 playbook回执 `pbr-6d77b32f40`
- `2026-04-19 04:32:49 +0800`
- `cycle=6`
- `log-sync-recover` 调用失败。
- `driver-run run_inspection_participating` 调用失败。
- 错误为 `curl: (7) Failed to connect to 127.0.0.1 port 8100: Connection refused`
- `2026-04-19 04:33:34 +0800`
- `cycle=7`
- 同类动作再次失败,错误相同。
- `2026-04-19 04:34:28 +0800`
- `cycle=8`
- `go_live=attention`
- `log_sync=full_capture`
- 夜跑停止,`reason=signoff_ready_candidate`
## 已确认的问题
- 夜跑期间存在控制面 API 短时离线或重启窗口。
- 自动恢复逻辑在 API 不可达时会直接失败,但日志里没有看到进一步的退避、跳过本轮、等待 API 恢复后的再确认闭环。
- 当时的“可签收候选”判断,掺杂了 API 短时不可达窗口,所以不能把这次夜跑结论直接当成正式签收证据。
## 这轮修复后的关联状态
- 当前中央控制面已经恢复正常。
- `runtime/cluster` 已恢复为 3 台有效执行节点。
- `detect/status` 已恢复远端日志回传。
- `mainland-controller-01` 当前已恢复 `100/100`
- `mainland-worker-01` 当前已进入活跃参与,中央已看到 `2/50`
## 明天继续看时,优先检查
- `docs/ops_center_runtime/night_runs/night_run_20260419_012929.log`
- 重点看 `04:32:49``04:34:28` 这段 API 拒绝连接窗口。
- `docs/ops_center_runtime/night_runs/night_run_20260419_012929/cycle_8/go_live.json`
- 确认 `go_live=attention` 的具体触发项。
- `docs/ops_center_runtime/night_runs/night_run_20260419_012929_report.md`
- 对照夜跑最终报告和原始日志,确认是否把“候选可签收”误当成“正式通过”。
## 下一步建议
- 补一条夜跑期间的 API 可用性守护:
- 发现 `127.0.0.1:8100` 不可达时,不立刻继续推进收口动作,先等待 API 恢复后重试。
- 把“候选可签收”和“正式可签收”拆开:
- 避免在 API 短时重启窗口里出现假阳性收口。

View File

@@ -0,0 +1,44 @@
# NIGHT RUN REPORT night_run_20260419_012929
- Base URL: `http://127.0.0.1:8100`
- Deadline: `2026-04-20 12:00:00 +0800`
- Stop Reason: `signoff_ready_candidate`
- Cycles: `8`
- Log Sync Recover Runs: `4`
- Inspection Runs: `4`
- Inspection Churn Runs: `0`
- Quick Rechecks: `4`
## Final Snapshot
- `go_live_status = attention`
- `publish_ready = false`
- `log_sync_state = full_capture`
- `issue_total = 0`
- `problem_runs_total = 0`
- `launchpad_status = `
- `launchpad_recommended_action = `
- `problem_run_code = `
## Summary JSON
```json
{
"cycles": 8,
"go_live_status": "attention",
"publish_ready": false,
"log_sync_state": "full_capture",
"log_sync_missing_node_codes": [],
"stack_status": "",
"issue_total": 0,
"blocking_issue_total": 0,
"issue_codes": [],
"launchpad_status": "",
"launchpad_recommended_action": "",
"problem_runs_total": 0,
"problem_run_code": "",
"scene_status": "",
"scene_line_count": 0,
"generated_at": "2026-04-19 04:34:28"
}
```

View File

@@ -0,0 +1,18 @@
{
"cycles": 8,
"go_live_status": "attention",
"publish_ready": false,
"log_sync_state": "full_capture",
"log_sync_missing_node_codes": [],
"stack_status": "",
"issue_total": 0,
"blocking_issue_total": 0,
"issue_codes": [],
"launchpad_status": "",
"launchpad_recommended_action": "",
"problem_runs_total": 0,
"problem_run_code": "",
"scene_status": "",
"scene_line_count": 0,
"generated_at": "2026-04-19 04:34:28"
}

View File

@@ -0,0 +1,816 @@
# domainCheck Ops Agent Protocol
## 1. 目标
这份文档用于冻结 `Node Agent <-> Overseas Control Plane` 的正式 contract。
适用范围:
- `POST /api/v1/ops/agent/tokens`
- `POST /api/v1/ops/agent/bootstrap-plan`
- `GET /api/v1/ops/nodes/{node_code}/handover`
- `POST /api/v1/ops/nodes/{node_code}/handover/bootstrap-plan`
- `POST /api/v1/ops/agent/register`
- `POST /api/v1/ops/agent/heartbeat`
- `POST /api/v1/ops/agent/pull`
- `POST /api/v1/ops/agent/jobs/{job_id}/start`
- `POST /api/v1/ops/agent/jobs/{job_id}/complete`
- `POST /api/v1/ops/agent/jobs/{job_id}/events`
设计原则:
- Agent 只执行声明过的结构化动作
- 控制面负责调度、门禁、编排和审计
- 所有回执都必须可重放、可去重、可死信化
---
## 2. 公共响应包裹
所有接口统一返回:
```json
{
"code": 0,
"message": "ok",
"detail_code": "",
"data": {}
}
```
约束:
- `code=0` 表示成功
- `code=1` 表示业务失败
- `detail_code` 用于结构化错误语义
- `message` 只承担可读说明,不承担机器判断主逻辑
常见 `detail_code`
- `agent_token_invalid`
- `agent_token_expired`
- `agent_token_node_mismatch`
- `ops_job_not_owned_by_agent`
- `ops_job_invalid_status_transition`
- `release_checksum_mismatch`
- `release_health_check_failed`
---
## 3. 认证与请求头
Agent 相关接口统一使用:
- `Content-Type: application/json`
- `X-Domaincheck-Agent-Token: <token>`
其中:
- `tokens`
- `bootstrap-plan`
不要求 Agent Token。
其余接口都要求 Token。
---
## 4. 公共节点载荷
`register``heartbeat` 当前共享 `_base_payload()`
最小字段:
```json
{
"node_code": "mainland-worker-02",
"region": "mainland",
"role": "worker",
"title": "mainland-worker-02",
"hostname": "host-a",
"ip": "10.0.0.12",
"agent_version": "0.1.0",
"capabilities": [
"service.start",
"service.stop",
"service.restart",
"service.status",
"health.snapshot",
"logs.collect",
"diagnostics.collect",
"deploy.release"
],
"labels": {},
"metadata": {
"service_names": {
"api": "domaincheck-api",
"worker": "domaincheck-worker",
"sync_agent": "domaincheck-sync-agent",
"node_agent": "domaincheck-node-agent"
},
"delivery_queue": {
"state": "healthy",
"label": "正常",
"reason": "当前没有待重试回执,也没有死信记录。",
"pending_count": 0,
"dead_letter_count": 0,
"last_flush_at": "",
"oldest_pending_at": "",
"oldest_pending_request_id": "",
"oldest_pending_kind": "",
"oldest_dead_letter_at": "",
"oldest_dead_letter_request_id": "",
"oldest_dead_letter_kind": ""
}
}
}
```
说明:
- `service_names` 是控制面识别节点服务拓扑的最小入口
- `delivery_queue` 是控制面识别 Agent 回执现场的最小入口
---
## 5. Bootstrap Contract
### 5.1 Issue Token
`POST /api/v1/ops/agent/tokens`
请求体最小字段:
```json
{
"node_code": "mainland-worker-02",
"issued_by": "web-ui",
"expires_in_hours": 72,
"metadata": {
"source": "ops-center"
}
}
```
返回体关键字段:
- `token`
- `token_preview`
- `record_id`
- `node_code`
- `expires_at`
- `created_at`
### 5.2 Bootstrap Plan
`POST /api/v1/ops/agent/bootstrap-plan`
请求体最小字段:
```json
{
"node_code": "mainland-worker-02",
"node_region": "mainland",
"node_role": "worker",
"issued_by": "web-ui",
"expires_in_hours": 72,
"control_plane_base_url": "https://ops.example.com",
"root_dir": "/opt/domaincheck",
"metadata": {
"source": "ops-center"
}
}
```
返回体关键字段:
- Token 相关字段
- `control_plane_base_url`
- `bootstrap_plan.node_code`
- `bootstrap_plan.node_region`
- `bootstrap_plan.node_role`
- `bootstrap_plan.root_dir`
- `bootstrap_plan.env_file`
- `bootstrap_plan.service_name`
- `bootstrap_plan.service_file`
- `bootstrap_plan.install_script_path`
- `bootstrap_plan.env_content`
- `bootstrap_plan.command_lines`
- `bootstrap_plan.command_block`
- `bootstrap_plan.health_checks`
- `bootstrap_plan.health_check_block`
- `bootstrap_plan.bootstrap_script_name`
- `bootstrap_plan.bootstrap_script_path`
- `bootstrap_plan.bootstrap_script_content`
- `bootstrap_plan.bootstrap_run_script_block`
约束:
- `bootstrap_plan` 是标准接入方案对象
- 页面、Codex、CLI 必须复用这一个对象
- 不允许各端再次手写 env 或 shell 逻辑
---
## 6. Runtime Contract
### 6.1 Register
`POST /api/v1/ops/agent/register`
语义:
- 校验 Token 与 `node_code`
- Upsert Agent 运行态
- 将节点推入托管目录候选态
最小成功返回字段:
- `node_code`
- `expires_at`
- `capabilities`
### 6.2 Heartbeat
`POST /api/v1/ops/agent/heartbeat`
语义:
- 刷新 `last_seen_at`
- 刷新节点身份、服务名和队列快照
- 维持控制面中的 Agent 在线态
最小成功返回字段:
- `node_code`
- `server_time`
- `expires_at`
### 6.3 Pull
`POST /api/v1/ops/agent/pull?limit=1`
请求体最小字段:
```json
{
"node_code": "mainland-worker-02"
}
```
返回体关键字段:
```json
{
"jobs": [
{
"id": 123,
"job_code": "ops-xxx",
"action": "health.snapshot",
"target_node_code": "mainland-worker-02",
"status": "dispatching",
"execution_mode": "remote-agent",
"payload": {},
"metadata": {},
"policy": {},
"steps": []
}
],
"count": 1
}
```
约束:
- Agent 只能拿到属于自己的任务
- Agent 不负责选择任务
- 调度权始终在控制面
### 6.3.1 Agent Job Envelope
为了避免 Agent 再从自然语言动作名里“猜执行上下文”,`pull.data.jobs[]` 当前已经按统一任务包裹返回。
当前 `pull.data` 顶层也会额外带:
- `protocol_version`
- `envelope_type`
- `node_code`
- `limit`
- `count`
推荐最小结构:
```json
{
"protocol_version": "ops-agent/v1",
"envelope_type": "agent_job",
"id": 123,
"job_id": 123,
"job_code": "ops-20260418-001",
"job_type": "ops_action",
"action": "logs.collect",
"target_node_code": "mainland-worker-02",
"status": "dispatching",
"execution_mode": "remote-agent",
"step_key": "worker_logs",
"step_title": "收集 Worker 日志",
"job_ref": {
"job_id": 123,
"job_code": "ops-20260418-001",
"action": "logs.collect",
"target_node_code": "mainland-worker-02"
},
"step_ref": {
"step_id": 456,
"step_key": "worker_logs",
"step_title": "收集 Worker 日志"
},
"payload": {
"service_name": "domaincheck-worker",
"lines": 120,
"include_agent_logs": false
},
"policy": {
"timeout_seconds": 120,
"stop_on_failure": true,
"auto_approve": true
},
"metadata": {
"requested_by": "playbook:inspection.standard",
"source": "ops-center"
},
"release_context": {
"release_id": 0,
"release_version": "",
"rollout_id": 0,
"rollout_code": ""
},
"focus_ref": {
"kind": "ops_job",
"job_id": 123,
"job_code": "ops-20260418-001",
"action": "logs.collect",
"target_node_code": "mainland-worker-02"
}
}
```
正式要求:
- Agent 必须优先消费:
- `action`
- `payload`
- `policy`
- Agent 不应通过:
- `step_title`
- `summary`
- `notes`
去反推真实执行参数
- 与发布相关的任务应通过:
- `release_context`
传递 release / rollout 关联,而不是让 Agent 自己查询“当前版本”
这层的意义是:
- `ops job`
- 仍是正式执行颗粒度
- `Agent Job Envelope`
- 是 Node Agent 拿到的稳定执行视图
这样同一套 Agent 才能同时承接:
- 标准巡检
- 日志收集
- 诊断采样
- Release 部署
- Rollout 回滚
### 6.4 Start
`POST /api/v1/ops/agent/jobs/{job_id}/start`
请求体最小字段:
```json
{
"node_code": "mainland-worker-02"
}
```
语义:
- `dispatching` 表示已派发
- `running` 表示节点已真实开工
### 6.5 Complete
`POST /api/v1/ops/agent/jobs/{job_id}/complete`
请求体最小字段:
```json
{
"node_code": "mainland-worker-02",
"client_request_id": "complete-ops-123-1",
"status": "success",
"stdout": "",
"stderr": "",
"result": {
"summary": "ok"
},
"error_message": ""
}
```
允许状态:
- `success`
- `failed`
- `partially_succeeded`
幂等约束:
- 使用 `client_request_id`
- 控制面写入 `ops_jobs.last_agent_complete_request_id`
- 同一完成回执可安全重放,不应再次制造副作用
推荐补充字段:
- `duration_ms`
- `result.summary_text`
- `result.focus_ref`
当前成功返回里也会额外带:
- `completion_summary.job_id`
- `completion_summary.job_code`
- `completion_summary.status`
- `completion_summary.status_label`
- `completion_summary.result_summary_text`
- `completion_summary.focus_ref`
- `completion_summary.deduplicated`
这样控制面在不展开 stdout/stderr 的情况下,也能直接把:
- 任务收口摘要
- 后续跳转落点
并入 activity / inspection / rollout 观察面。
### 6.6 Events
`POST /api/v1/ops/agent/jobs/{job_id}/events`
请求体最小字段:
```json
{
"node_code": "mainland-worker-02",
"client_event_id": "event-ops-123-checksum-1",
"step_id": 0,
"event_type": "deploy_checksum_verified",
"level": "info",
"message": "checksum ok",
"payload": {
"checksum": "sha256:..."
}
}
```
去重约束:
- 使用 `client_event_id`
- 控制面通过唯一索引去重
- 同一事件可安全重放,不应重复落库
推荐补充字段:
- `occurred_at`
- `summary_text`
- `focus_ref`
当前成功返回里也会额外带:
- `event`
- 即标准化后的事件对象
- 内含 `event_key / summary_text / occurred_at / focus_ref`
这样事件流就不再只是“原始日志点”,而能直接成为:
- playbook run events
- rollout events
- activity-stream
共同消费的现场片段。
---
## 7. Agent 本地补发队列
当前主链路已经正式具备:
- `pending` 队列
- `dead-letter` 队列
- 定时 `_flush_delivery_queue()`
- 永久性错误转死信
当前重点覆盖:
- `jobs/{id}/complete`
- `jobs/{id}/events`
队列状态:
- `healthy`
- `retrying`
- `dead_letter`
语义:
- `healthy`:无积压,无死信
- `retrying`存在待补发回执Agent 会继续自动重放
- `dead_letter`:存在永久失败记录,需人工介入
控制面消费方式:
- 节点维度:
- `delivery_queue_state`
- `delivery_queue_label`
- `delivery_queue_reason`
- `delivery_queue_pending_count`
- `delivery_queue_dead_letter_count`
- 汇总维度:
- `queue_retrying_nodes`
- `queue_dead_letter_nodes`
- `queue_pending_records`
- `queue_dead_letter_records`
### 7.1 当前控制面已可见的最小现场
当前至少已经可以通过:
- `GET /api/v1/ops/nodes`
看到每台托管节点的队列现场:
```json
{
"node_code": "mainland-worker-02",
"delivery_queue_state": "dead_letter",
"delivery_queue_label": "死信 2",
"delivery_queue_reason": "当前存在 2 条死信记录,建议优先查看节点日志或诊断编排。",
"delivery_queue_pending_count": 0,
"delivery_queue_dead_letter_count": 2,
"delivery_queue_last_flush_at": "2026-04-18 06:10:00",
"delivery_queue_oldest_pending_at": "",
"delivery_queue_oldest_pending_request_id": "",
"delivery_queue_oldest_pending_kind": "",
"delivery_queue_oldest_dead_letter_at": "2026-04-18 05:59:00",
"delivery_queue_oldest_dead_letter_request_id": "complete-ops-123-1",
"delivery_queue_oldest_dead_letter_kind": "job_complete"
}
```
这已经足够让:
- 页面显示“节点存在死信”
- `overview / driver-feed / codex-brief` 产出驾驶建议
- CLI 快速判断现场是不是要先走日志或诊断
但这还不够支撑正式运维,因为它只能“看见死信”,还不能“处理死信”。
### 7.2 Delivery Queue Record 正式对象
后续控制面不应再把死信理解成一个纯计数器,而要把每条待补发 / 死信记录升级成正式对象。
推荐最小结构:
```json
{
"record_id": "dq-mainland-worker-02-20260418-001",
"node_code": "mainland-worker-02",
"state": "dead_letter",
"request_kind": "job_complete",
"client_request_id": "complete-ops-123-1",
"job_id": 123,
"job_code": "ops-20260418-001",
"target_api": "/api/v1/ops/agent/jobs/123/complete",
"detail_code": "ops_job_invalid_status_transition",
"error_message": "当前任务状态不允许 complete",
"attempt_count": 6,
"first_queued_at": "2026-04-18 05:58:00",
"last_attempt_at": "2026-04-18 05:59:00",
"next_retry_at": "",
"payload_preview": {
"status": "success"
},
"response_preview": {
"code": 1,
"detail_code": "ops_job_invalid_status_transition"
}
}
```
正式约束:
- `record_id`
- 是控制面侧唯一主键
- `client_request_id`
- 是 Agent 幂等键
- `detail_code`
- 是死信聚类主键,不能只靠 `message`
- `payload_preview / response_preview`
- 用于页面和 Codex 快速判断,不必默认展开完整原始报文
推荐状态:
- `pending`
- `retrying`
- `dead_letter`
- `replayed`
- `discarded`
### 7.3 死信操作面正式入口
为了让“看见死信”之后不用回节点本地处理,推荐把操作面固定成下面这组接口。
当前已落地的第一阶段能力:
- `GET /api/v1/ops/nodes/{node_code}/delivery-queue`
- `GET /api/v1/ops/nodes/{node_code}/delivery-queue/records`
当前控制面返回的记录可见性为:
- `record_visibility=head_only`
也就是:
- 当前已经能稳定查看节点级队列总览
- 也能看到 `pending / dead_letter` 的头部记录摘要
- 但还没有把节点本地全量 `pending/*.json / dead-letter/*.json` 正式同步到控制面
所以这两条 GET 入口现在属于“正式只读观察面”,而不是完整操作面。
#### a. 单节点队列总览
- `GET /api/v1/ops/nodes/{node_code}/delivery-queue`
最小返回体:
```json
{
"node_code": "mainland-worker-02",
"summary": {
"state": "dead_letter",
"pending_count": 0,
"dead_letter_count": 2,
"last_flush_at": "2026-04-18 06:10:00"
},
"oldest_pending_record": {},
"oldest_dead_letter_record": {}
}
```
#### b. 队列记录列表
- `GET /api/v1/ops/nodes/{node_code}/delivery-queue/records`
推荐筛选参数:
- `state=pending|retrying|dead_letter|replayed|discarded`
- `request_kind=job_complete|job_event`
- `detail_code=...`
- `group_by=detail_code|request_kind|target_api`
- `limit=50`
当带 `group_by` 时,返回值应优先给出聚类摘要,而不是只返回平铺明细。
#### c. 单条死信重放
- `POST /api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/replay`
当前已落地,但要明确当前阶段约束:
- 控制面仍然是 `record_visibility=head_only`
- 所以单条动作目前只允许针对“当前可见头部记录”
- 真正的执行不是控制面直接改远端文件,而是创建正式 `ops job`
- 由目标节点 `Node Agent` 执行 `delivery.queue.replay`
最小请求体:
```json
{
"requested_by": "web-ui",
"reason": "确认任务状态已修复,重放这条 complete 回执"
}
```
#### d. 批量重放
- `POST /api/v1/ops/nodes/{node_code}/delivery-queue/replay`
当前已落地为正式操作面。
推荐请求体:
```json
{
"requested_by": "codex",
"selector": {
"state": "dead_letter",
"detail_code": "ops_job_invalid_status_transition"
},
"limit": 20
}
```
#### e. 丢弃死信
- `POST /api/v1/ops/nodes/{node_code}/delivery-queue/records/{record_id}/discard`
当前已落地,但与单条重放一样,仍然只允许针对当前可见头部死信记录发起单条动作。
最小请求体:
```json
{
"discarded_by": "web-ui",
"reason": "确认这条回执不再需要补发"
}
```
#### f. 主动冲刷队列
- `POST /api/v1/ops/nodes/{node_code}/delivery-queue/flush`
当前已落地为正式操作面,执行方式同样是:
- 控制面创建 `ops job`
- 目标节点 `Node Agent` 执行 `delivery.queue.flush`
语义:
- 不是“强行成功”
- 而是立即触发一次 Agent 补发冲刷
- 结果仍然回到 `pending / retrying / dead_letter / replayed`
### 7.4 为什么必须做成正式操作面
这层不是为了让页面多一个按钮,而是为了保证:
- 页面可以处理死信
- CLI 可以处理死信
- 海外 Codex 驾驶员可以处理死信
三者都不需要绕回:
- 手工 SSH 登录节点
- 手工删本地文件
- 手工重放某条 HTTP 请求
正式规则应该固定成:
- “死信查看” 走控制面对象
- “死信重放 / 丢弃 / 冲刷” 走控制面对象
- Agent 只负责执行,不负责决定如何处理死信
---
## 8. Job Status Enum
当前 Agent 主链路约束:
- `queued`
- `dispatching`
- `running`
- `success`
- `failed`
- `partially_succeeded`
语义:
- `queued`:任务已创建,尚未派发
- `dispatching`:控制面已派发,但节点尚未确认开工
- `running`:节点已真实执行
- `success`:成功完成
- `failed`:失败完成
- `partially_succeeded`:部分成功,需关注
---
## 9. 实现边界
Agent 只执行已声明动作:
- `service.start`
- `service.stop`
- `service.restart`
- `service.status`
- `health.snapshot`
- `logs.collect`
- `diagnostics.collect`
- `deploy.release`
不允许控制面长期依赖任意 shell 下发。
`shell executor` 只能作为受限兜底能力存在,并必须挂审批与审计。

Some files were not shown because too many files have changed in this diff Show More