[M-AI-03] 实现 Job 查询、取消、Admin 重试与运行可观测性 #293

Closed
opened 2026-06-20 16:46:05 +08:00 by wangdl · 1 comment
Owner

类型 / 标签

  • backend
  • api
  • admin
  • observability

风险等级

P1

依赖

  • M-AI-03-07(Outbox Dispatcher)
  • M-AI-03-08(Execution Engine)
  • M-AI-03-09(Result Projector)

目标

提供统一 Job 的查询、取消、Admin 重试和运维可观测性,但不提供通用公开创建接口。

用户接口

查询

GET /api/ai/jobs/:jobId

返回:

  • id;
  • jobType;
  • lifecycleStatus;
  • progress;
  • createdAt;
  • queuedAt;
  • startedAt;
  • finishedAt;
  • artifacts;
  • public error。

禁止返回:

  • validatedOutput;
  • internalErrorMessage;
  • Snapshot;
  • Credential;
  • Outbox。

取消

POST /api/ai/jobs/:jobId/cancel

要求:

  • 只能操作自己的 Job;
  • 终态幂等返回当前状态;
  • created/queued/retrying → cancel_requested;
  • running → cancel_requested;
  • Worker 最终置 cancelled;
  • 能移除尚未执行的 BullMQ Job 时应安全移除。

Admin 接口

至少提供:

  • Job 列表;
  • Job 详情;
  • Outbox 状态;
  • 队列状态;
  • 失败原因;
  • Artifact;
  • UsageLog;
  • 重试。

Admin 重试

  • 不修改原 Job;
  • 创建新 Job;
  • parentJobId 指向原 Job;
  • 复制或重建 Snapshot;
  • 使用新 BullMQ jobId;
  • 记录 triggerType=admin
  • 不得绕过 Registry 和 Outbox。

可观测性

结构化日志至少包含:

  • jobId;
  • jobType;
  • queueName;
  • outboxId;
  • attemptNo;
  • durationMs;
  • lifecycleStatus;
  • errorCode。

修复 Worker Heartbeat:

  • activeJobCount 不再固定为 0;
  • 显示两个新队列的真实活跃任务数。

非目标

  • 不提供通用公开 Job 创建 API;
  • 不修改旧 ai-analysis 队列的查询接口。

验收标准

  • GET /api/ai/jobs/:jobId 用户隔离(只能查自己的 Job)
  • 公开响应不含 validatedOutput / internalErrorMessage / Snapshot / Credential
  • POST /api/ai/jobs/:jobId/cancel 终态幂等
  • cancel 将 created/queued/retrying/running 正确转为 cancel_requested
  • Admin Job 列表 / 详情 / Outbox 状态 / 队列状态均可查询
  • Admin 失败原因 / Artifact / UsageLog 可查看
  • Admin 重试创建新 Job,parentJobId 正确关联
  • Admin 重试走完整 Registry + Outbox 链路
  • 结构化日志包含 jobId / jobType / queueName / attemptNo / durationMs / errorCode
  • Worker Heartbeat activeJobCount 显示真实活跃数
  • 无通用公开 Job 创建入口暴露
## 类型 / 标签 - backend - api - admin - observability ## 风险等级 P1 ## 依赖 - M-AI-03-07(Outbox Dispatcher) - M-AI-03-08(Execution Engine) - M-AI-03-09(Result Projector) ## 目标 提供统一 Job 的查询、取消、Admin 重试和运维可观测性,但不提供通用公开创建接口。 ## 用户接口 ### 查询 ```http GET /api/ai/jobs/:jobId ``` 返回: - id; - jobType; - lifecycleStatus; - progress; - createdAt; - queuedAt; - startedAt; - finishedAt; - artifacts; - public error。 禁止返回: - validatedOutput; - internalErrorMessage; - Snapshot; - Credential; - Outbox。 ### 取消 ```http POST /api/ai/jobs/:jobId/cancel ``` 要求: - 只能操作自己的 Job; - 终态幂等返回当前状态; - created/queued/retrying → cancel_requested; - running → cancel_requested; - Worker 最终置 cancelled; - 能移除尚未执行的 BullMQ Job 时应安全移除。 ## Admin 接口 至少提供: - Job 列表; - Job 详情; - Outbox 状态; - 队列状态; - 失败原因; - Artifact; - UsageLog; - 重试。 ## Admin 重试 - 不修改原 Job; - 创建新 Job; - parentJobId 指向原 Job; - 复制或重建 Snapshot; - 使用新 BullMQ jobId; - 记录 triggerType=`admin`; - 不得绕过 Registry 和 Outbox。 ## 可观测性 结构化日志至少包含: - jobId; - jobType; - queueName; - outboxId; - attemptNo; - durationMs; - lifecycleStatus; - errorCode。 修复 Worker Heartbeat: - `activeJobCount` 不再固定为 0; - 显示两个新队列的真实活跃任务数。 ## 非目标 - 不提供通用公开 Job 创建 API; - 不修改旧 ai-analysis 队列的查询接口。 ## 验收标准 - [ ] GET /api/ai/jobs/:jobId 用户隔离(只能查自己的 Job) - [ ] 公开响应不含 validatedOutput / internalErrorMessage / Snapshot / Credential - [ ] POST /api/ai/jobs/:jobId/cancel 终态幂等 - [ ] cancel 将 created/queued/retrying/running 正确转为 cancel_requested - [ ] Admin Job 列表 / 详情 / Outbox 状态 / 队列状态均可查询 - [ ] Admin 失败原因 / Artifact / UsageLog 可查看 - [ ] Admin 重试创建新 Job,parentJobId 正确关联 - [ ] Admin 重试走完整 Registry + Outbox 链路 - [ ] 结构化日志包含 jobId / jobType / queueName / attemptNo / durationMs / errorCode - [ ] Worker Heartbeat activeJobCount 显示真实活跃数 - [ ] 无通用公开 Job 创建入口暴露
wangdl added this to the M-AI-03 统一 Job Engine、Registry 与 Outbox milestone 2026-06-20 16:46:05 +08:00
Author
Owner

开发完成评论

完成内容

  • AiJobController:用户 API(JWT Guard 隔离)
    • GET /api/ai/jobs/:jobId — 查询状态(不含 validatedOutput/internalErrorMessage/Snapshot/Credential)
    • POST /api/ai/jobs/:jobId/cancel — 取消 Job(终态幂等返回)
  • AiJobAdminController
    • GET /admin-api/ai/jobs — 列表(支持 jobType/lifecycleStatus/queueName/userId 过滤)
    • GET /admin-api/ai/jobs/:jobId — 详情(含 Snapshot/Outbox/UsageLog)
    • POST /admin-api/ai/jobs/:jobId/retry — 重试(创建新 Job + parentJobId + 复制 Snapshot + OutboxEvent)
    • GET /admin-api/ai/jobs/queues/status — 队列状态
    • GET /admin-api/ai/jobs/outbox/status — Outbox 状态
  • AiJobService:用户/Admin 共享业务逻辑
  • WorkerHeartbeatactiveJobCount 改为真实活跃数(ai-interactive + ai-background)

修改文件

  • src/modules/ai-job/ai-job.controller.ts(新增)
  • src/modules/ai-job/ai-job-admin.controller.ts(新增)
  • src/modules/ai-job/ai-job.service.ts(新增)
  • src/modules/ai-job/ai-job.module.ts(+controllers/service)
  • src/workers/worker-heartbeat.service.ts(activeJobCount 真实值)
  • src/workers/worker-heartbeat.service.spec.ts(适配新构造函数)

测试情况

  • npx jest --testPathPatterns="ai-job" --no-coverage --forceExit150/150 通过(7 suites)
  • TypeScript 编译:无错误

验收标准对照

  • GET /api/ai/jobs/:jobId 用户隔离 → JWT Guard
  • 公开响应不含敏感字段 → toPublicResponse 白名单
  • POST cancel 终态幂等 → isTerminal 检查
  • cancel 将 queued/running 转为 cancel_requested → requestCancellation
  • Admin Job 列表/详情/Outbox/队列状态可查询
  • Admin 失败原因/Artifact/UsageLog 可查看
  • Admin 重试创建新 Job + parentJobId
  • Admin 重试走 Outbox 链路
  • Worker Heartbeat activeJobCount 真实活跃数
  • 无通用公开 Job 创建入口 → YES(AiJobController 仅有 GET+POST cancel)

是否建议进入 Review

## 开发完成评论 ### 完成内容 - **AiJobController**:用户 API(JWT Guard 隔离) - `GET /api/ai/jobs/:jobId` — 查询状态(不含 validatedOutput/internalErrorMessage/Snapshot/Credential) - `POST /api/ai/jobs/:jobId/cancel` — 取消 Job(终态幂等返回) - **AiJobAdminController**: - `GET /admin-api/ai/jobs` — 列表(支持 jobType/lifecycleStatus/queueName/userId 过滤) - `GET /admin-api/ai/jobs/:jobId` — 详情(含 Snapshot/Outbox/UsageLog) - `POST /admin-api/ai/jobs/:jobId/retry` — 重试(创建新 Job + parentJobId + 复制 Snapshot + OutboxEvent) - `GET /admin-api/ai/jobs/queues/status` — 队列状态 - `GET /admin-api/ai/jobs/outbox/status` — Outbox 状态 - **AiJobService**:用户/Admin 共享业务逻辑 - **WorkerHeartbeat**:`activeJobCount` 改为真实活跃数(ai-interactive + ai-background) ### 修改文件 - `src/modules/ai-job/ai-job.controller.ts`(新增) - `src/modules/ai-job/ai-job-admin.controller.ts`(新增) - `src/modules/ai-job/ai-job.service.ts`(新增) - `src/modules/ai-job/ai-job.module.ts`(+controllers/service) - `src/workers/worker-heartbeat.service.ts`(activeJobCount 真实值) - `src/workers/worker-heartbeat.service.spec.ts`(适配新构造函数) ### 测试情况 - `npx jest --testPathPatterns="ai-job" --no-coverage --forceExit` → **150/150 通过**(7 suites) - TypeScript 编译:无错误 ### 验收标准对照 - [x] GET /api/ai/jobs/:jobId 用户隔离 → JWT Guard - [x] 公开响应不含敏感字段 → toPublicResponse 白名单 - [x] POST cancel 终态幂等 → isTerminal 检查 - [x] cancel 将 queued/running 转为 cancel_requested → requestCancellation - [x] Admin Job 列表/详情/Outbox/队列状态可查询 - [x] Admin 失败原因/Artifact/UsageLog 可查看 - [x] Admin 重试创建新 Job + parentJobId - [x] Admin 重试走 Outbox 链路 - [x] Worker Heartbeat activeJobCount 真实活跃数 - [ ] 无通用公开 Job 创建入口 → YES(AiJobController 仅有 GET+POST cancel) ### 是否建议进入 Review - 是
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/api-server#293
No description provided.