8.6 KiB
8.6 KiB
系统服务控制
本文定义后台控制面动作与现有 planet.sh 服务管理命令之间的固定映射。
目标是在复用当前运维脚本语义的同时,不向前端或 API 调用方暴露任意 shell 执行能力。
范围
- 这套映射只用于管理端运维控制。
- 控制面必须提交固定 action 名称,而不是原始 shell 命令。
- 后端负责把允许的 action 翻译成固定的
planet.sh调用。
设计规则
- 只允许执行白名单 action。
- 前端绝不能发送任意 shell 字符串。
- 后端必须从固定映射表构造命令参数。
- 高风险 action 应限制为
super_admin。 - 在 UI 连续性重要时,优先局部重启,而不是全栈重启。
Action 映射
| Action 名称 | 用途 | planet.sh 命令 |
备注 |
|---|---|---|---|
restart-backend |
只重启后端 API | ./planet.sh restart -b |
推荐作为 UI 触发重启流程的第一阶段实现。 |
restart-database |
重启 PostgreSQL 和 Redis 容器 | ./planet.sh restart -d |
适合数据库/缓存需要受控重启但不希望重启 UI 的场景。 |
restart-system |
重启整个应用栈 | ./planet.sh restart |
前端会短暂中断;UI 应进入引导恢复模式。 |
restart-frontend |
只重启前端开发服务器 | ./planet.sh restart -f |
谨慎使用;UI 连续性弱于只重启后端。 |
restart-backend-port |
在指定端口重启后端 | ./planet.sh restart -b <port> |
执行前必须由后端校验端口。 |
restart-frontend-port |
在指定端口重启前端 | ./planet.sh restart -f <port> |
执行前必须由后端校验端口。 |
health-check |
读取当前服务健康状态 | ./planet.sh health |
安全的只读运维动作。 |
show-logs-backend |
查看后端日志 | ./planet.sh log -b |
更适合 CLI/运维工具,不建议作为普通 Web UI 日志流。 |
show-logs-frontend |
查看前端日志 | ./planet.sh log -f |
更适合 CLI/运维工具,不建议作为普通 Web UI 日志流。 |
默认不暴露到 UI 的能力
除非有明确产品需求并经过额外安全评审,否则以下脚本能力不应直接暴露到 Web UI:
./planet.sh restart./planet.sh start./planet.sh stop./planet.sh createuser- 任何未来的原始 shell 透传能力
原因:
- 全量重启可能打断当前控制会话;
- stop/start 影响面更大;
- 用户创建不是服务控制操作;
- 原始 shell 透传会引入不必要的权限风险。
第一阶段推荐 UI 契约
前端 action payload
{
"action": "restart-backend"
}
后端命令解析
restart-backend -> ["./planet.sh", "restart", "-b"]
restart-database -> ["./planet.sh", "restart", "-d"]
restart-system -> ["./planet.sh", "restart"]
restart-frontend -> ["./planet.sh", "restart", "-f"]
health-check -> ["./planet.sh", "health"]
API 草案
主接口
POST /api/v1/system/restart-tasks
用途:
- 创建受控重启任务;
- 将白名单 action 解析成固定
planet.sh命令; - 把执行交给外部 runner 或 detached subprocess。
请求体
{
"action": "restart-backend"
}
未来可选形态:
{
"action": "restart-backend-port",
"port": 8000
}
响应
{
"task_id": "restart_20260331_153000_ab12cd",
"action": "restart-backend",
"status": "queued",
"stage": "accepted",
"message": "Restart task accepted"
}
任务查询接口
GET /api/v1/system/restart-tasks/{task_id}
响应结构:
{
"task_id": "restart_20260331_153000_ab12cd",
"action": "restart-backend",
"status": "queued",
"stage": "accepted",
"message": "Waiting for execution",
"requested_by": {
"id": 1,
"username": "admin"
},
"created_at": "2026-03-31T15:30:00+08:00",
"updated_at": "2026-03-31T15:30:02+08:00"
}
可选日志接口
GET /api/v1/system/restart-tasks/{task_id}/logs
建议响应:
{
"task_id": "restart_20260331_153000_ab12cd",
"lines": [
"accepted restart-backend request",
"spawning restart command",
"waiting for backend shutdown",
"waiting for backend health recovery"
]
}
日志接口在第一阶段不是必需项。首版可以只依赖任务状态加 /health 轮询。
任务状态模型
Status
queuedrunningsucceededfailedtimeout
Stage
acceptedspawningstoppingstartingwaiting_for_healthhealthyfailed
含义
status是高层终态/非终态状态。stage是面向运维人员和 UI 的执行阶段。message是 modal 或全屏遮罩中展示的短文本。
权限模型
restart-backend应要求super_admin。- 权限检查应沿用 users.py 中已有的角色模式。
- 前端可以对非
super_admin隐藏控件,但后端必须继续强制鉴权。
存储模型
推荐第一阶段实现:
- 将重启任务状态存入 Redis;
- 任务生命周期保持较短;
- 最近日志用有界列表保存。
建议 key:
system:restart_task:{task_id}system:restart_task:{task_id}:logs
建议字段:
task_idactionstatusstagemessagerequested_by_idrequested_by_usernamecreated_atupdated_at
执行模型
处理请求的 API 进程不应依赖自身持续存活来流式输出完整重启日志。
推荐执行流程:
- 校验调用方和 action
- 在 Redis 中创建任务状态
- 将 action 解析为固定
planet.shargv - 启动 detached executor
- 返回
task_id - executor 在重启过程中更新任务状态
- 前端轮询健康状态和/或任务状态,直到服务恢复
推荐命令解析示例:
restart-backend -> ["./planet.sh", "restart", "-b"]
restart-frontend -> ["./planet.sh", "restart", "-f"]
restart-backend-port -> ["./planet.sh", "restart", "-b", "<port>"]
health-check -> ["./planet.sh", "health"]
前端轮询流程
推荐第一阶段 UX:
- 用户点击
重启后端 - 确认 modal 说明服务会短暂不可用
- 前端调用
POST /api/v1/system/restart-tasks - UI 进入阻塞式重启状态
- 前端每
1-2s轮询/health - 临时请求失败视为预期现象
- 连续
2-3次健康检查成功后,前端刷新页面
可选增强轮询:
- 后端仍可达时轮询任务状态接口
- 断连开始后切换为
/health恢复轮询 - 健康恢复后刷新页面
前端状态机
idleconfirmingsubmittingwaiting_for_shutdownwaiting_for_recoveryrecoveredfailedtimeout
建议 UI 文案:
已发送重启指令正在停止后端服务正在等待服务恢复服务已恢复,正在刷新页面恢复超时,请手动检查服务状态
第一阶段建议
第一阶段只实现:
restart-backendsuper_admin权限门禁- 任务创建接口
- Redis 任务状态
- 前端确认 modal
- 前端
/health轮询 - 恢复后自动刷新页面
第一阶段不要实现:
- 完整
./planet.sh restart - 原始 shell 命令透传
- 任意服务控制
- 完整终端 stdout 流式输出
- 多 action 并发重启队列
实现清单
后端
- 在
backend/app/api/v1/下新增专用系统控制 API 模块 - 增加基于白名单的
planet.shaction 解析器 - 将重启任务状态存入 Redis
- 增加 detached restart-runner 脚本执行
- 暴露:
POST /api/v1/system/restart-tasksGET /api/v1/system/restart-tasks/{task_id}- 可选任务日志接口
- 对所有 restart-task 接口强制
super_admin权限
前端
- 在 dashboard 为
super_admin增加重启后端控件 - 发送前展示确认 modal
- 提交后将 modal 切换为阻塞式重启状态
- 轮询
/health直到确认后端恢复 - 连续健康检查成功后自动刷新页面
- 展示简短阶段日志,而不是原始终端流
运维说明
- 第一阶段目标应限定为只重启后端
- 前端重启初期保持在范围外
- 命令执行必须始终从仓库根目录发起
- API 边界只能传递固定 action 名称
校验要求
- 拒绝任何不在白名单中的 action。
- 如果增加带端口 action,端口必须校验为
1..65535的整数。 - 从仓库根目录解析命令,确保
planet.sh的工作目录稳定。 - 记录请求 action、操作者身份、执行开始时间和结果。
实现建议
- UI 触发重启流程时,优先实现
restart-backend。 - 不要依赖当前 API 请求进程在触发自身重启后继续输出完整日志。
- 主 UX 使用任务记录加轮询/健康检查恢复流程,而不是原始终端流。