149 lines
6.1 KiB
Markdown
149 lines
6.1 KiB
Markdown
|
|
# 设计说明 — 脚本库全局执行进度 + Telegram 结果通知
|
|||
|
|
|
|||
|
|
**日期**: 2026-06-08
|
|||
|
|
**基线**: `main@3f995a7`
|
|||
|
|
**参考 UI**: [VSnackbarQueue Promise](https://vuetifyjs.com/zh-Hans/components/snackbar-queue/#promise) · [VProgressLinear chunks](https://vuetifyjs.com/zh-Hans/components/progress-linear/#chunks) · [VAlert 可关闭](https://vuetifyjs.com/zh-Hans/components/alerts/#section-7c7b578b)
|
|||
|
|
|
|||
|
|
## 背景与目标
|
|||
|
|
|
|||
|
|
运维在脚本库对 300+ 台执行命令时,需要:
|
|||
|
|
|
|||
|
|
1. **点击执行后立即返回**,不阻塞对话框/页面,可在其他页面继续操作。
|
|||
|
|
2. **全局顶部**展示执行进度(流动状进度条 +「已进行 3 台,剩余 363 台」)。
|
|||
|
|
3. **执行结束**时:浏览器提醒 + 短促提示音;可点击关闭,**1 秒渐隐**。
|
|||
|
|
4. **Telegram** 推送汇总:成功 N / 失败 M;失败项含**服务器名称、退出码、原因摘要**(可多条)。
|
|||
|
|
|
|||
|
|
## 现状差距
|
|||
|
|
|
|||
|
|
| 能力 | 现状 | 缺口 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| 后台执行 | `POST /api/scripts/exec` **同步 await** 全部批次(366 台可阻塞数十秒~数分钟) | 须改为「创建 execution → 立即返回 → 后台 dispatch」 |
|
|||
|
|
| 进度 UI | ScriptsPage 底部「批量执行状态」+ 10s 轮询 | 须全局 Snackbar Queue + 细粒度进度 |
|
|||
|
|
| 实时推送 | Push 有 `/ws/sync`;脚本**无** WS | 须新增 `script_progress` 广播或复用 alerts WS |
|
|||
|
|
| Telegram | 仅有 `send_telegram_sync_complete` | 须新增 `send_telegram_script_complete` + 设置项 |
|
|||
|
|
| 完成提醒 | 终态仅 `snackbar(warning)` | 须 Alert + 声音 + 渐隐动画 |
|
|||
|
|
|
|||
|
|
## 方案对比
|
|||
|
|
|
|||
|
|
### A. 后台执行 + WebSocket 进度(推荐)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
POST /exec → 202 + execution_id
|
|||
|
|
↓
|
|||
|
|
asyncio.create_task(run_batches)
|
|||
|
|
↓ 每完成一台/一批
|
|||
|
|
broadcast_script_progress → /ws/alerts 或 /ws/scripts
|
|||
|
|
↓ 终态
|
|||
|
|
send_telegram_script_complete + WS terminal event
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优点**:进度实时、与 Push 模式一致、Snackbar 可流畅更新。
|
|||
|
|
**缺点**:需改后端执行模型 + WS 协议。
|
|||
|
|
|
|||
|
|
### B. 仅前端全局轮询
|
|||
|
|
|
|||
|
|
API 仍同步,或改为后台但前端 2s 轮询 `GET /executions/{id}`。
|
|||
|
|
|
|||
|
|
**优点**:改动小。
|
|||
|
|
**缺点**:366 台时 API 仍可能长时间不返回;轮询粗、流量大;不符合「先返回再执行」。
|
|||
|
|
|
|||
|
|
**选定 A**。
|
|||
|
|
|
|||
|
|
## 接口与数据模型
|
|||
|
|
|
|||
|
|
### API 变更
|
|||
|
|
|
|||
|
|
| 端点 | 变更 |
|
|||
|
|
|------|------|
|
|||
|
|
| `POST /api/scripts/exec` | 创建 execution + `init_live` 后**立即返回** `{ id, status: "running", progress: "0/N" }`;dispatch 在 `asyncio.create_task` |
|
|||
|
|
| `POST /api/scripts/executions/{id}/retry` | 同上异步模式 |
|
|||
|
|
| `GET /api/scripts/executions/{id}` | 不变(轮询兜底) |
|
|||
|
|
|
|||
|
|
**兼容**:长任务(`long_task`)逻辑保持;短任务也走同一异步路径。
|
|||
|
|
|
|||
|
|
### WebSocket 消息(扩展 `/ws/alerts` 或新建 `/ws/scripts`)
|
|||
|
|
|
|||
|
|
推荐 **扩展 `/ws/alerts`**(App 已连接),新增 type:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"type": "script_progress",
|
|||
|
|
"execution_id": 6,
|
|||
|
|
"label": "磁盘检查",
|
|||
|
|
"status": "running",
|
|||
|
|
"done": 3,
|
|||
|
|
"success": 3,
|
|||
|
|
"failed": 0,
|
|||
|
|
"total": 366,
|
|||
|
|
"remaining": 363
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
终态:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"type": "script_complete",
|
|||
|
|
"execution_id": 6,
|
|||
|
|
"status": "partial",
|
|||
|
|
"success": 363,
|
|||
|
|
"failed": 3,
|
|||
|
|
"total": 366,
|
|||
|
|
"failed_preview": [
|
|||
|
|
{ "server_id": 1, "name": "srv-a", "exit_code": 1, "summary": "Connection timed out" }
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`done` = 已有终态结果的台数(含失败);`success` 沿用 `execution_progress_summary` 语义(失败不计入 success)。
|
|||
|
|
|
|||
|
|
### Telegram
|
|||
|
|
|
|||
|
|
新增 `send_telegram_script_complete()`,参照 `send_telegram_sync_complete`:
|
|||
|
|
|
|||
|
|
- 设置项:`NOTIFY_SCRIPT_COMPLETE`(默认 `true`,Settings 可关)
|
|||
|
|
- 正文:脚本名/命令摘要、操作人、成功/失败/总计、耗时
|
|||
|
|
- **失败明细**:每台一行 — `名称 · exit码 · 原因摘要`(HTML escape + sanitize)
|
|||
|
|
- 超过 Telegram 4096 字符:首批 20 条 +「…及其他 N 台,详见 Nexus #/scripts 执行 #id」
|
|||
|
|
- 触发点:`script_execution_store.apply_update(..., terminal=True)` 或 dedicated `on_execution_terminal` hook
|
|||
|
|
|
|||
|
|
### 前端全局 UI
|
|||
|
|
|
|||
|
|
| 组件 | 用途 |
|
|||
|
|
|------|------|
|
|||
|
|
| `VSnackbarQueue` | 全局顶部(`location="top"`),每任务一条 queue item |
|
|||
|
|
| `VProgressLinear` `buffer-value` + `indeterminate` 交替 | 「流动状」进度;`model-value = done/total*100` |
|
|||
|
|
| `VAlert` closable + `@click:close` + CSS transition 1s | 完成提醒条(成功/部分失败/全失败配色) |
|
|||
|
|
| `Audio` / `new Audio('/app/notify.mp3')` | 终态播放一次(用户可浏览器静音) |
|
|||
|
|
|
|||
|
|
**Snackbar 文案示例**(进行中):
|
|||
|
|
|
|||
|
|
> 磁盘检查 · 已进行 3 台,剩余 363 台
|
|||
|
|
|
|||
|
|
**Promise 模式**:queue 项在 `script_complete` 时 resolve,切换为 Alert 或关闭 snackbar 并弹出 Alert。
|
|||
|
|
|
|||
|
|
**状态管理**:新建 `useScriptExecutionQueue`(Pinia 或 composable singleton),ScriptsPage / SchedulesPage 提交后只调用 `queue.track(executionId, label, total)`,**移除**页面内 `trackedExecs` 面板(或保留「详情」链接)。
|
|||
|
|
|
|||
|
|
## 安全与性能
|
|||
|
|
|
|||
|
|
- WS 消息仅 JWT 已连接管理员可见;不含完整 stderr(Telegram 同样截断)。
|
|||
|
|
- 后台 task 须捕获异常写 execution `failed`,避免 silent hang。
|
|||
|
|
- 366 台 Telegram 分条/截断,防 flood。
|
|||
|
|
- 单 worker:`create_task` 绑定 primary worker 约定(与现有 background tasks 一致)。
|
|||
|
|
|
|||
|
|
## 验收标准
|
|||
|
|
|
|||
|
|
- [ ] 选 366 台点执行 → **1s 内**关闭对话框,顶部出现进度 Snackbar。
|
|||
|
|
- [ ] 切换至 Dashboard/其他页,进度条仍更新。
|
|||
|
|
- [ ] 文案显示「已进行 X 台,剩余 Y 台」,X+Y=总数(进行中);Y 随完成递减。
|
|||
|
|
- [ ] 全部结束:短促提示音 + 顶部 Alert「成功 363 台,失败 3 台」;点击后 **1s 渐隐**。
|
|||
|
|
- [ ] Telegram 收到汇总 + 3 台失败名称与原因。
|
|||
|
|
- [ ] Settings 关闭 `NOTIFY_SCRIPT_COMPLETE` 时不发 Telegram。
|
|||
|
|
- [ ] 长任务 / retry / 临时命令 行为一致。
|
|||
|
|
|
|||
|
|
## 非目标(本期不做)
|
|||
|
|
|
|||
|
|
- 多 execution 合并为一条 Telegram(每台 execution 一条)。
|
|||
|
|
- 浏览器 Push Notification API(仅站内 Alert + 声音)。
|
|||
|
|
- 修改 `success/total` 进度语义。
|