1739f7a2f9
为 server/manage/getNodes 返回节点级今日、本月与累计流量统计, 并在节点管理页名称悬浮层展示上行、下行和合计流量。 同时为自动上线补齐单节点同步入口,在管理端保存、 批量更新以及 REST/WS 心跳后立即同步 show 状态, 避免复制节点后开启自动上线仍需等待定时任务。 另优化管理端前端 Docker 发布流程,默认仅构建 amd64, 并收敛 BuildKit 缓存导出以缩短发布时间
6.5 KiB
6.5 KiB
变更提案: admin-frontend-node-auto-online-immediate-sync
元信息
类型: 修复
方案类型: implementation
优先级: P1
状态: 已规划
创建: 2026-04-28
1. 需求
背景
节点管理页复制节点后,新节点会保留原节点的 auto_online 状态但被复制接口强制设为隐藏。管理员修改新节点信息并安装节点后,即使自动上线处于开启状态,节点也不会立即显示,需要手动关闭自动上线、打开显隐、再重新开启自动上线。
代码事实:
ManageController::copy()复制节点后设置show = 0。NodeEditorDialog保存会提交show与auto_online,但后端save()只落库,不主动执行自动上线同步。ServerAutoOnlineService::sync()目前只由sync:server-auto-online定时命令每 5 分钟调用。- REST 节点心跳
ServerService::touchNode()只更新在线缓存,不会触发自动上线同步;WebSocket 状态上报还绕过了touchNode()直接写缓存。
目标
- 自动上线开启的节点在管理端保存、开启自动上线或节点心跳上报后,立即按当前在线状态和墙检测状态同步
show。 - 保持现有定时任务兜底能力,避免依赖管理员手动切换显隐。
- 保持墙检测自动隐藏规则不被绕过。
约束条件
时间约束: 无
性能约束: 单节点心跳只能同步当前节点,不能触发全量扫描
兼容性约束: 保持 sync:server-auto-online 命令输出结构不变
业务约束: 自动上线仍以 available_status 和墙状态为准;未开启 auto_online 的节点不改变手动显隐
验收标准
ServerAutoOnlineService支持单节点同步,并复用定时全量同步的同一套判定逻辑。- 管理端保存节点、开启自动上线、批量开启自动上线后,若节点当前为在线或待同步且未被墙检测否决,应立即
show=1。 - 节点心跳上报后,若该节点开启自动上线,应立即同步
show,不必等待 Scheduler。 - 被墙状态或
gfw_auto_hidden未恢复正常时,自动上线不会把节点重新显示。 - 单元测试覆盖单节点同步和心跳触发场景。
2. 方案
技术方案
将 ServerAutoOnlineService 中的自动上线判定抽出为可复用的 syncServer(Server $server) 单节点入口。全量定时命令继续调用 sync(),内部复用同一判定函数。
在两个关键触发点调用单节点同步:
- 管理端
ManageController的save()、update()、batchUpdate()在节点开启auto_online后立即调用。 ServerService::touchNode()在节点心跳刷新后,如果节点开启auto_online,立即调用;WebSocket 状态上报改为复用touchNode()。
影响范围
涉及模块:
- server-auto-online: 抽取单节点同步入口,复用全量同步逻辑
- admin-server-manage: 保存/开关/批量更新自动上线时立即同步
- server-heartbeat: REST 与 WebSocket 节点心跳后触发当前节点同步
- tests: 补充自动上线单节点与心跳行为验证
预计变更文件: 5
风险评估
| 风险 | 等级 | 应对 |
|---|---|---|
| 节点心跳频繁导致额外数据库写入 | 中 | 只在 auto_online=true 时执行;状态无变化时不保存 |
保存接口中 show 与 auto_online 同时提交时语义冲突 |
低 | 自动上线开启时以自动同步判定为准,符合 UI 中显隐开关被托管的文案 |
| 墙检测自动隐藏被误清除 | 中 | 单节点同步复用原有 isGfwBlocked/isGfwHeld 判定,只在正常状态时清除 hold |
方案取舍
唯一方案理由: 问题根因在后端自动上线语义只由定时任务触发;把同步能力收敛到服务层并在业务事件中调用,可以同时覆盖管理端保存、开关和节点真实上线心跳。
放弃的替代路径:
- 仅前端保存后强制提交 show=1: 会绕过离线/被墙判断,且无法覆盖节点稍后才心跳上线的场景。
- 缩短 Scheduler 间隔: 仍不是立即上线,并增加全量扫描频率。
- 复制节点时默认关闭 auto_online: 会改变复制语义,仍要求管理员额外操作。
回滚边界: 可独立回退 ServerAutoOnlineService 单节点入口、ManageController 调用点和 ServerService::touchNode 调用点;数据库结构不变。
3. 技术设计
架构设计
flowchart TD
A[管理端保存/开启自动上线] --> B[ManageController]
C[REST/WS 节点心跳上报] --> D[ServerService::touchNode]
B --> E[ServerAutoOnlineService::syncServer]
D --> E
F[sync:server-auto-online] --> G[ServerAutoOnlineService::sync]
G --> E
E --> H[按 available_status + GFW 状态同步 show]
API 设计
不新增外部 API。现有接口保持不变:
POST /server/manage/savePOST /server/manage/updatePOST /server/manage/batchUpdate- 节点心跳/报告接口
数据模型
不新增字段。
4. 核心场景
场景: 复制节点后自动上线立即生效
模块: admin-frontend / server-auto-online
条件: 新节点由复制产生,show=0,auto_online=1,节点已经心跳在线且未被墙检测否决。
行为: 管理员在节点管理页编辑并保存该节点。
结果: 后端保存后立即执行单节点自动上线同步,节点 show=1,前端刷新列表后显示为上线。
场景: 节点稍后才上线
模块: server-heartbeat / server-auto-online
条件: 节点保存时尚未心跳,auto_online=1,show=0。
行为: 节点安装完成并上报心跳。
结果: REST 与 WebSocket 心跳都会通过 touchNode() 更新在线缓存并立即同步当前节点,节点不需要等待下一轮 Scheduler。
5. 验证策略
verifyMode: test-first
reviewerFocus:
- app/Services/ServerAutoOnlineService.php 单节点与全量同步是否共用判定逻辑
- app/Services/ServerService.php 与 app/WebSocket/NodeEventHandlers.php 心跳触发是否只影响 auto_online 节点
- app/Http/Controllers/V2/Admin/Server/ManageController.php 管理端更新后的同步时机
testerFocus:
- vendor/bin/phpunit tests/Unit/ServerAutoOnlineServiceTest.php
- npm --prefix admin-frontend run build
uiValidation: none
riskBoundary:
- 不修改数据库结构
- 不修改节点列表视觉结构
- 不改变未开启 auto_online 节点的手动显隐行为
6. 成果设计
N/A。此任务不包含视觉产出。