v2.5 功能测试通过,待加上docker镜像
This commit is contained in:
@@ -11,4 +11,4 @@ v2.5 的核心变化:
|
||||
- `specs/mvp/v2.5/v2.5_design.md`:总体架构、关键机制(head IP file / watchdog / 用户隔离 / 任务流)。
|
||||
- `specs/mvp/v2.5/v2.5_api.md`:API 设计(用户、任务、队列、日志)与鉴权约定。
|
||||
- `specs/mvp/v2.5/v2.5_acceptance.md`:开发/部署/验收流程与可验证标准。
|
||||
|
||||
- `specs/mvp/v2.5/v2.5_summary.md`:v2.5 已实现内容总结(本次迭代做了什么、验收结果、已知限制)。
|
||||
|
||||
3
specs/mvp/v2.5/notices.md
Normal file
3
specs/mvp/v2.5/notices.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 记录问题
|
||||
1. task 、 submission id 里加上 user name
|
||||
2. 补全端到端测试用例,各种正常和异常用例,边界情况测试
|
||||
229
specs/mvp/v2.5/v2.5_dev_plan.md
Normal file
229
specs/mvp/v2.5/v2.5_dev_plan.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# MVP v2.5 开发计划(TDD 驱动)
|
||||
|
||||
本文是 v2.5 的**工程化开发计划**,强调“先写测试,再写实现”(TDD),并将每个里程碑拆成**可独立验收**的小闭环。
|
||||
|
||||
输入依据:
|
||||
- 路线图:`specs/mvp/mvp_roadmap_v2.md`
|
||||
- v2.5 设计:`specs/mvp/v2.5/v2.5_design.md`
|
||||
- v2.5 API 草案:`specs/mvp/v2.5/v2.5_api.md`
|
||||
- v2.5 验收:`specs/mvp/v2.5/v2.5_acceptance.md`
|
||||
|
||||
v2.5 约束(已确认):
|
||||
- **不扩展 TaskSpec**:沿用 v2.0/v2.1 的 YAML 结构化字段与语义。
|
||||
- **不支持自定义 reward function / 不支持用户自定义 verl 代码**。
|
||||
- 训练输入(verl 代码、HF cache、datasets)统一使用 `/private/common/...`。
|
||||
- 多用户隔离 v2.5 **先只隔离 jobs 输出目录**:`/private/users/<uid>/jobs/<ray_submission_id>/...`。
|
||||
|
||||
---
|
||||
|
||||
## 0. TDD 规范(所有功能都遵循)
|
||||
|
||||
### 0.1 测试分层
|
||||
|
||||
1) **单元测试(fast)**
|
||||
- 纯 Python 逻辑:DB、鉴权、ID、路径派生、head.json 解析/TTL、watchdog 决策逻辑。
|
||||
- 目标:不依赖真实 Ray、不依赖 docker、不依赖网络。
|
||||
|
||||
2) **组件测试(中等)**
|
||||
- FastAPI 路由:使用 `fastapi.testclient.TestClient`(现有 v2.0 已采用)。
|
||||
- 目标:验证 auth/权限隔离、API 行为、状态机。
|
||||
|
||||
3) **端到端(慢/手工或脚本)**
|
||||
- 在 `argus@h1` 上通过 scripts/compose 跑一次“head publish → worker auto-connect → API submit”闭环。
|
||||
- 目标:验证无状态 worker + watchdog 的真实行为。
|
||||
|
||||
### 0.2 测试约定
|
||||
|
||||
- 测试目录:`src/mvp/py/tests/`
|
||||
- 新增功能必须先补齐测试用例,并让其在未实现时失败(红)。
|
||||
- 实现最小改动让测试变绿(绿)。
|
||||
- 重构/去重复(重构)。
|
||||
|
||||
> 注:现有测试通过 `src/mvp/py/tests/conftest.py` 注入 ray stub,确保单测不依赖真实 ray 包;v2.5 新增模块也应复用此模式。
|
||||
|
||||
---
|
||||
|
||||
## 1. 里程碑拆分(v2.5 = 4 个可验证闭环)
|
||||
|
||||
### M1:User 表/Token 表 + 基础鉴权(不影响现有内部 token 兼容)
|
||||
|
||||
**目标**
|
||||
- 引入 user/token 的持久化与鉴权映射(token → user_id)。
|
||||
- 兼容现有 `Authorization: Bearer <MVP_INTERNAL_TOKEN>` 的“单租户模式”,避免一次性破坏 v2.0 用法:
|
||||
- v2.5 可以先支持两种 token 模式:
|
||||
- legacy:环境变量 `MVP_INTERNAL_TOKEN`(全局单租户);
|
||||
- user token:DB 内签发 token(多用户)。
|
||||
- admin 能创建用户、签发 token、禁用用户。
|
||||
|
||||
**TDD 用例(先写测试)**
|
||||
|
||||
单测:
|
||||
- `test_user_db_create_disable()`
|
||||
- 创建用户 ACTIVE;禁用后状态变为 DISABLED;重复创建返回冲突或幂等(按最终约定)。
|
||||
- `test_token_hashing()`
|
||||
- 签发 token 时 DB 中只保存 hash,不保存明文。
|
||||
|
||||
API 测试(TestClient):
|
||||
- `test_admin_create_user_and_issue_token()`
|
||||
- admin token 可创建用户并签发 token(明文 token 只返回一次)。
|
||||
- `test_disabled_user_token_rejected()`
|
||||
- 用户被禁用后,使用旧 token 调用 API 返回 401/403。
|
||||
|
||||
**实现落点(建议模块)**
|
||||
- `argus.service.auth`:token 校验与 user_id 解析(兼容 legacy 模式)
|
||||
- `argus.service.db`:新增 `users`、`api_tokens` 表与 CRUD
|
||||
- `argus.service.app`:新增 user 管理 endpoints(admin scope)
|
||||
- `configs/dev.yaml`:补充 admin token/env 相关配置(保持 YAML 风格)
|
||||
|
||||
**验收点**
|
||||
- `v2.5_acceptance.md`:U1 可通过自动化 API 测试覆盖。
|
||||
|
||||
---
|
||||
|
||||
### M2:Task 绑定 user_id + API 可见性隔离(仍不改 TaskSpec)
|
||||
|
||||
**目标**
|
||||
- 提交 task 时由 token 推导 `user_id`,写入 `tasks.user_id`。
|
||||
- task 查询/取消/日志默认只允许 owner;他人访问返回 404(避免泄露存在性)。
|
||||
- queue 默认只返回当前用户队列;admin 可查询全局队列(可选)。
|
||||
|
||||
**TDD 用例(先写测试)**
|
||||
|
||||
单测:
|
||||
- `test_tasks_table_has_user_id()`:创建任务必须落 `user_id`,且 `list_queue(user_id=...)` 只返回该用户任务。
|
||||
|
||||
API 测试:
|
||||
- `test_task_visibility_isolated()`
|
||||
- user A 创建 task;user B 查询 `/api/v2/tasks/{id}` 返回 404;
|
||||
- user B cancel/logs 也返回 404。
|
||||
- `test_queue_isolated()`
|
||||
- A/B 各自创建 task;`GET /api/v2/queue` 只看到自己的。
|
||||
|
||||
**实现落点**
|
||||
- `argus.service.app`:为 task endpoints 增加 user scope
|
||||
- `argus.service.db`:tasks 表增加 user_id 字段、索引、按 user 过滤的查询方法
|
||||
- `argus.service.scheduler`:pick_next_runnable_task 等仍按“全局 FIFO”或“按 user FIFO”
|
||||
- v2.5 先保持“全局 FIFO”最简单(但 API queue 视角是按 user 过滤)。
|
||||
|
||||
**验收点**
|
||||
- `v2.5_acceptance.md`:U2 可通过 API 测试覆盖。
|
||||
|
||||
---
|
||||
|
||||
### M3:Jobs 输出目录按 user 隔离(只改输出,不改输入)
|
||||
|
||||
**目标**
|
||||
- Ray Job 的 job_root 目录由服务端统一计算到:
|
||||
- `/private/users/<uid>/jobs/<ray_submission_id>/...`
|
||||
- TaskSpec 内与输入相关的路径字段必须是 `/private/common/...`(v2.5 输入统一 common)。
|
||||
- 任何用户无法通过 TaskSpec 指定输出写到非 user jobs 目录(避免越权写)。
|
||||
|
||||
**TDD 用例(先写测试)**
|
||||
|
||||
单测:
|
||||
- `test_job_root_derivation_per_user()`
|
||||
- 给定 user_id 与 ray_submission_id,派生 job_root 固定且正确。
|
||||
- `test_reject_non_common_inputs()`
|
||||
- TaskSpec 中 train_file / val_file / code_path / hf 路径等若不以 `/private/common/` 开头则拒绝(HTTP 400)。
|
||||
|
||||
API 测试:
|
||||
- `test_job_dir_written_under_user_jobs()`
|
||||
- 提交 task 后,在 DB 或 submit payload 中能看到 job_root 在 user jobs 下(可通过 mock RayJobTool.submit 捕获 spec)。
|
||||
|
||||
**实现落点(建议最小侵入)**
|
||||
- 在 service 层派生 `job_root` 并注入到 RayJobTool/builders(而不是让用户从 TaskSpec 指定)。
|
||||
- RayJobTool `_job_dir()` 改为接收“job_root 生成器”或直接接收 `job_root` 参数(由服务层提供)。
|
||||
- 目标:保持 RayJobTool 的职责清晰:提交 Ray job;路径策略由 service 决定。
|
||||
|
||||
**验收点**
|
||||
- `v2.5_acceptance.md`:U3/U4 可通过 API/单测覆盖。
|
||||
|
||||
---
|
||||
|
||||
### M4:Stateless Ray Node Pool(head.json + worker watchdog)+ 端到端脚本验证
|
||||
|
||||
**目标**
|
||||
- head 启动后持续写入 `/private/ray/discovery/<cluster_name>/head.json`(包含 TTL)。
|
||||
- worker 容器内运行 watchdog(或启动脚本 + watchdog),无需平台显式传 head 地址:
|
||||
- 读取 head.json(存在且未过期)→ `ray start --address=<head_ip>:<gcs_port>`
|
||||
- head.json 变化 → `ray stop` + `ray start` 重连
|
||||
- 在 dev 环境(docker compose)提供一键脚本复现(e2e)。
|
||||
|
||||
**TDD 用例(先写测试)**
|
||||
|
||||
单测(不跑真实 ray):
|
||||
- `test_head_json_read_validate_ttl()`
|
||||
- 文件不存在/过期 → 返回“不可用”
|
||||
- 未过期 → 返回 head 地址
|
||||
- `test_watchdog_decision_on_change()`
|
||||
- head_ip 变化 → 触发重连动作
|
||||
- only updated_at 变化(地址不变)→ 不重连(或按策略重连,需确定)
|
||||
|
||||
组件/脚本级测试(可选):
|
||||
- 如果 watchdog 用 Python 实现,可对“执行命令”层做 stub(不真正跑 `ray start`),只验证会调用什么命令。
|
||||
|
||||
端到端脚本(手工/慢):
|
||||
- 提供脚本 `scripts/run_all_v25_stateless.sh`(命名示例):
|
||||
1) 起 head(Ray head + API)
|
||||
2) 启动 head publisher(写 head.json)
|
||||
3) 起 2 个 worker(每个 4 GPU),worker 只跑 watchdog,不传 head 地址
|
||||
4) `ray status` 显示 1 head + 2 worker 且 GPU=8
|
||||
5) 通过 API 创建用户/签发 token,提交 PPO/GRPO/SFT
|
||||
6) 重启 head(或更新 head.json 指向新地址)验证 worker 自动重连
|
||||
|
||||
**实现落点(建议实现策略)**
|
||||
|
||||
为了可测试性(TDD),推荐把“读 head.json/判定 TTL/生成 ray start 命令”做成 Python 模块:
|
||||
- `argus.ray.discovery`:read/write head.json(原子写、TTL)
|
||||
- `argus.ray.worker_watchdog`:watch loop(polling + change detection),执行命令可注入(便于单测 stub)
|
||||
|
||||
脚本层保持薄:
|
||||
- `scripts/` 负责 docker exec / compose 编排与进程守护;
|
||||
- watchdog 进程由容器内 python 模块运行(更可测、更易移植到生产平台的 entrypoint/command)。
|
||||
|
||||
**验收点**
|
||||
- `v2.5_acceptance.md`:A1/A2/A3 主要通过 e2e 脚本 + dashboard/日志验证。
|
||||
|
||||
---
|
||||
|
||||
## 2. 回归策略(确保 v2.0 不被破坏)
|
||||
|
||||
在 v2.5 过程中保留并持续回归以下用例(至少单测覆盖):
|
||||
- 旧的内部 token 模式仍可访问 `GET /api/v2/queue` 与提交 task(若决定保留兼容)。
|
||||
- scheduler 的“资源不足 → PENDING_RESOURCES → 延迟重试”行为不变(现有 `test_scheduler.py` 覆盖)。
|
||||
- `ray entrypoint_resources` 强制 driver 落 worker(继续使用 `worker_node` 自定义资源)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 交付清单(代码/脚本/文档)
|
||||
|
||||
### 3.1 代码
|
||||
- user/tokens:DB schema + auth + API endpoints
|
||||
- tasks:绑定 user_id + 权限隔离
|
||||
- job_root:按 user jobs 输出目录派生(输入仍 common)
|
||||
- discovery/watchdog:head.json + worker 自愈
|
||||
|
||||
### 3.2 scripts(dev e2e)
|
||||
- head:启动 Ray head + head publisher
|
||||
- workers:以无状态方式启动(不传 head addr)+ watchdog
|
||||
- `run_all`:一键跑通(含 API submit + 查询 + cancel + 观察队列)
|
||||
|
||||
### 3.3 文档
|
||||
- 更新 `specs/mvp/v2.5/*`(设计/API/验收/开发计划)
|
||||
- 补充 `src/mvp/README.md` 的 v2.5 使用方式(如需要)
|
||||
|
||||
---
|
||||
|
||||
## 4. 关键待确认点(开始实现前必须定稿)
|
||||
|
||||
1) **legacy token 是否继续兼容**
|
||||
- 方案 A:保留 `MVP_INTERNAL_TOKEN`(单租户)+ 新增 user token(多租户)
|
||||
- 方案 B:v2.5 直接切换到 user token(破坏兼容,但更清晰)
|
||||
|
||||
2) **调度公平性**
|
||||
- v2.5 先全局 FIFO(简单);后续 v3 再引入 per-user 公平调度/配额。
|
||||
|
||||
3) **head.json 的生产写入者**
|
||||
- 方案 A:与 API 同进程线程(最少组件)
|
||||
- 方案 B:独立进程(更独立、易运维)
|
||||
|
||||
132
specs/mvp/v2.5/v2.5_e2e_test_cases.md
Normal file
132
specs/mvp/v2.5/v2.5_e2e_test_cases.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# MVP v2.5 端到端测试用例(正常/异常/边界)
|
||||
|
||||
本用例集目标:覆盖 v2.5 的关键能力与边界条件(User + jobs 隔离 + stateless node pool + API 队列调度)。
|
||||
|
||||
约束(v2.5 已确认):
|
||||
- TaskSpec 不扩展;不支持 reward_fn;不支持用户自定义 verl 代码。
|
||||
- 输入统一 `/private/common/...`;用户隔离先只隔离 `/private/users/<uid>/jobs/...` 输出。
|
||||
|
||||
---
|
||||
|
||||
## 0. 环境前置
|
||||
|
||||
远端目录示例:
|
||||
- `argus@h1:/home2/argus/infra/mvp/src/mvp/`
|
||||
|
||||
共享目录(宿主机):
|
||||
- `/home2/argus/infra/mvp/shared/`
|
||||
|
||||
容器内路径约定:
|
||||
- `/private` 为共享存储挂载点
|
||||
|
||||
需要:
|
||||
- GPU 0-7 可用
|
||||
- 3 容器:head(无 GPU)+ 2 worker(各 4 GPU)
|
||||
|
||||
---
|
||||
|
||||
## 1. 正常用例(Happy Path)
|
||||
|
||||
### HP-1:v2.5 全链路(PPO → GRPO → SFT,串行)
|
||||
|
||||
步骤:
|
||||
1) `cd /home2/argus/infra/mvp/src/mvp/scripts`
|
||||
2) `MVP_INTERNAL_TOKEN=<admin_token> RESET_DB=1 ./run_all_v25_api.sh`
|
||||
|
||||
期望:
|
||||
- Ray dashboard 显示 3 nodes(head+2 workers),GPU 总数 8。
|
||||
- 3 个 task 最终为 `SUCCEEDED`。
|
||||
- 输出目录存在且按用户隔离:
|
||||
- `/private/users/<uid>/jobs/<ray_submission_id>/{config,logs,checkpoints,debug}`
|
||||
|
||||
### HP-2:Driver 不在 head 跑
|
||||
|
||||
验证点(任选一种):
|
||||
- Ray job 的 driver node IP 不等于 head 容器 IP;
|
||||
- 或日志/调度信息显示 entrypoint_resources 生效(driver 在 worker)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 异常用例(Error Cases)
|
||||
|
||||
### E-Auth-1:缺 token
|
||||
|
||||
请求:
|
||||
- `GET /api/v2/queue` 不带 `Authorization` 头
|
||||
|
||||
期望:
|
||||
- 返回 401(missing bearer token)
|
||||
|
||||
### E-Auth-2:无效 token
|
||||
|
||||
请求:
|
||||
- `Authorization: Bearer <random>`
|
||||
|
||||
期望:
|
||||
- 返回 401(invalid token)
|
||||
|
||||
### E-Auth-3:用户禁用后拒绝访问
|
||||
|
||||
步骤:
|
||||
1) admin 创建用户 `bob` 并签发 token
|
||||
2) admin 禁用 `bob`
|
||||
3) 用 bob token 请求 `/api/v2/queue`
|
||||
|
||||
期望:
|
||||
- 返回 403(user disabled)
|
||||
|
||||
### E-Isolation-1:跨用户访问 task 资源(不泄露存在性)
|
||||
|
||||
步骤:
|
||||
1) alice 提交 task 得到 `task_id`
|
||||
2) bob 查询 `/api/v2/tasks/{task_id}`
|
||||
|
||||
期望:
|
||||
- 返回 404(task not found)
|
||||
|
||||
### E-Input-1:输入路径不在 /private/common(v2.5 约束)
|
||||
|
||||
请求:
|
||||
- 提交 taskspec 但 `train_file` 或 `code_path` 不以 `/private/common/` 开头
|
||||
|
||||
期望:
|
||||
- 返回 400,并给出具体字段错误(例如 `train_file must start with /private/common/`)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 边界用例(Boundary)
|
||||
|
||||
### B-Queue-1:资源不足时不提交 Ray(PENDING_RESOURCES)
|
||||
|
||||
步骤:
|
||||
1) 构造任务需求 `nnodes=3` 且 `n_gpus_per_node=4`(total 12 GPU)
|
||||
2) 提交后轮询状态
|
||||
|
||||
期望:
|
||||
- task 进入 `PENDING_RESOURCES`(服务侧 pending,不向 Ray submit)
|
||||
- 具备 `next_run_at`
|
||||
|
||||
### B-Cancel-1:任务取消(QUEUED/RUNNING)
|
||||
|
||||
步骤:
|
||||
1) 提交一个较长 steps 的任务(确保有机会 RUNNING)
|
||||
2) 调用 `POST /api/v2/tasks/{task_id}:cancel`
|
||||
|
||||
期望:
|
||||
- task state 为 `CANCELED`
|
||||
- attempt 中 `ray_status` 最终为 `STOPPED`(或 Ray 侧停止)
|
||||
|
||||
---
|
||||
|
||||
## 4. 可执行回归脚本
|
||||
|
||||
见:
|
||||
- `src/mvp/scripts/run_e2e_v25_cases.sh`
|
||||
|
||||
脚本覆盖:
|
||||
- HP-1
|
||||
- E-Auth-1/E-Auth-2/E-Input-1
|
||||
- E-Isolation-1
|
||||
- B-Queue-1
|
||||
- B-Cancel-1(best-effort)
|
||||
|
||||
92
specs/mvp/v2.5/v2.5_summary.md
Normal file
92
specs/mvp/v2.5/v2.5_summary.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# MVP v2.5 迭代总结(已落地)
|
||||
|
||||
本文档总结 v2.5 在 v2.0/v2.1/v2.2…基础上完成的能力、实现点、验收方式与已知限制,便于回顾与后续版本迭代对齐。
|
||||
|
||||
## 目标与边界
|
||||
|
||||
v2.5 的核心目标:
|
||||
- 引入 **User Management(用户管理)**:基于 token 的鉴权与任务级隔离(“只隔离 jobs”)。
|
||||
- 引入 **Stateless Ray Node Pool(无状态 Ray worker 池)**:worker 不依赖平台下发 head 地址,自动发现并连接/自愈。
|
||||
- 保持 **TaskSpec(v1.1 同款 YAML 格式)不扩展**:本迭代不支持 reward function、自定义 verl 代码等。
|
||||
|
||||
明确不做(v2.5 约束):
|
||||
- 不支持 TaskSpec 扩展(例如 `reward_fn_path` 等)。
|
||||
- 不支持用户自定义 verl/hf/dataset 的隔离或自定义路径:**统一使用 `/private/common/...`** 的公共资源。
|
||||
- 用户隔离仅覆盖 **任务与产物目录**(jobs),不覆盖 HF cache、datasets 等公共缓存。
|
||||
|
||||
## 关键能力(对外表现)
|
||||
|
||||
### 1) 多用户鉴权与任务隔离
|
||||
- API 仍使用内部 `Authorization: Bearer <token>` 方式:
|
||||
- 管理员 token 来自环境变量 `MVP_INTERNAL_TOKEN`(admin)。
|
||||
- 业务用户 token 由管理员通过 API 下发并持久化到 SQLite。
|
||||
- 用户隔离策略:
|
||||
- 非管理员用户只能查询/取消/拉取日志 **自己的 task**;跨用户访问返回 404(不泄露存在性)。
|
||||
- 训练产物落盘隔离:Ray job 目录统一写入 `/private/users/<user_id>/jobs/<ray_submission_id>/...`。
|
||||
|
||||
### 2) task_id / submission_id 带用户名
|
||||
- 新任务 ID 规则:`mvp2-<user>-<workload>-<YYYYMMDD-HHMMSS>-<suffix>`
|
||||
- Ray submission id(attempt)规则:`<task_id>--aNN`,因此自然包含用户名。
|
||||
- 作用:Dashboard/日志/落盘目录可读性更强,便于按用户追踪和审计。
|
||||
|
||||
### 3) “无状态 worker 池”与 head 地址发现
|
||||
- Head 在共享存储写入 **head 地址文件**(例如 `head.json`),worker 通过 watchdog:
|
||||
- 轮询发现 head 地址
|
||||
- 自动 `ray start --address ...` 加入集群
|
||||
- 掉线后自动重连(watchdog 自愈)
|
||||
- 达成效果:在生产环境中,即使 worker 容器由算力平台创建(只提供 SSH 纳管),也能通过共享存储实现连接与自愈。
|
||||
|
||||
### 4) 任务调度:队列 + Ray Job 提交 + 状态回传
|
||||
- API 提交任务后进入 SQLite 队列,由后台 scheduler 逐个提交到 Ray(默认 `max_running_tasks=1`)。
|
||||
- Scheduler 持续轮询 Ray job 状态并回写任务状态(RUNNING/SUCCEEDED/FAILED/CANCELED)。
|
||||
- 资源不足的“可重试失败”处理:
|
||||
- 针对 VERL 的 fail-fast(`Total available GPUs ... is less than total desired GPUs ...`)或集群资源不足,
|
||||
任务进入 `PENDING_RESOURCES` 并设置 `next_run_at`,按 `retry_interval_s` 周期重试。
|
||||
|
||||
## 关键实现点(工程化落地)
|
||||
|
||||
### 存储与目录约定(容器内视角)
|
||||
- 共享根路径统一为 `/private`(对齐生产挂载)。
|
||||
- v2.5 强约束:TaskSpec 的以下字段必须以 `/private/common/` 开头:
|
||||
- `code_path` / `train_file` / `val_file`
|
||||
- 公共目录(示例):
|
||||
- `/private/common/hf`:HF 缓存
|
||||
- `/private/common/datasets`:训练数据(必要时通过 symlink 指向已有缓存目录复用下载)
|
||||
- `/private/common/db/mvp.sqlite3`:队列与用户信息(SQLite)
|
||||
- `/private/common/logs`:API / watchdog 日志
|
||||
- `/private/users/<uid>/jobs/...`:用户作业产物(隔离)
|
||||
|
||||
### Ray 拓扑与“head 不跑训练”
|
||||
- Head 启动为管理节点(CPU/GPU=0),避免训练任务落到 head。
|
||||
- Worker 节点具备 GPU(示例:2 个 worker * 每个 4 GPU)。
|
||||
- driver 通过 `entrypoint_resources`(例如 `worker_node: 1`)强制落 worker。
|
||||
|
||||
### 部署脚本与可重复执行
|
||||
提供完整脚本链路,覆盖:
|
||||
- 清理 legacy 环境、起停容器、启动 Ray head
|
||||
- head discovery publisher、worker watchdog 启动与状态检查
|
||||
- 数据/模型/代码准备(幂等、可复用已有下载)
|
||||
- 启动 API server(并支持 RESET_DB)
|
||||
- API 方式连续提交 PPO/GRPO/SFT 并等待完成
|
||||
|
||||
代表性脚本:
|
||||
- `src/mvp/scripts/run_all_v25_api.sh`:v2.5 happy-path 端到端(含重建集群、准备资源、起 API、提交 3 类任务)
|
||||
- `src/mvp/scripts/run_e2e_v25_cases.sh`:在 happy-path 基础上增加鉴权/隔离/输入校验/资源不足/取消等用例
|
||||
|
||||
## 验收与测试(已通过)
|
||||
|
||||
### 单元测试(本机 venv)
|
||||
- `.venv/bin/python -m pytest`
|
||||
- 覆盖率阈值:>= 90%
|
||||
|
||||
### 远端端到端(h1)
|
||||
- 在 `argus@h1:/home2/argus/infra/mvp/src/mvp/scripts` 执行:
|
||||
- `MVP_INTERNAL_TOKEN=mvp-dev-token RESET_DB=1 ./run_e2e_v25_cases.sh`
|
||||
- 结果:happy-path(PPO/GRPO/SFT)完成,且异常/边界用例验证通过(鉴权、跨用户隔离、输入校验、资源不足转 PENDING_RESOURCES、取消任务等)。
|
||||
|
||||
## 已知问题与后续建议
|
||||
|
||||
- `max_running_tasks=1` 会让队列中的任务在前序 RUNNING 时保持 QUEUED,这在“资源不足”边界测试里需要显式清空/取消前序任务,或接受该行为作为设计的一部分。
|
||||
- 当前仍是 SQLite 单点;后续若要 HA/水平扩展,可在 v2.6+ 引入更强的持久化与多副本(例如 Postgres/etcd)。
|
||||
- API server / watchdog 目前以脚本方式守护;后续可进一步统一为 systemd/supervisor(或平台侧守护)并补齐健康检查与告警。
|
||||
|
||||
Reference in New Issue
Block a user