Files
getDomain/docs/ops_center_runtime/HANDOFF_20260420_1920.md
Your Name 7cbde2aa78 d
2026-04-22 14:13:21 +08:00

564 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 核测试机当成主算力机。”