fix: ADR-003 cancel_requested 信号语义 + BullMQ retry 范围 + CreateJobInput 补全
- §1.1.1: 明确 cancel_requested 不是独立生命周期状态,是 running 上的信号字段 - §5.5: Engine 内部 retry(业务级)vs BullMQ retry(进程崩溃)的分工表 - §2.4: CreateJobInput 对齐 #289 规格(新增 triggerType/parentJobId) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
88b35d0d18
commit
8b6c7cef72
@ -48,6 +48,31 @@ M-AI-03 的目标是在 M-AI-02 Schema Expand 之上,纯代码层实现统一
|
|||||||
| `failed` | 执行失败且重试耗尽 | 是 | `AiJobLifecycleRepository.markFailed()` |
|
| `failed` | 执行失败且重试耗尽 | 是 | `AiJobLifecycleRepository.markFailed()` |
|
||||||
| `cancelled` | 用户/系统取消 | 是 | `AiJobLifecycleRepository.markCancelled()` |
|
| `cancelled` | 用户/系统取消 | 是 | `AiJobLifecycleRepository.markCancelled()` |
|
||||||
|
|
||||||
|
#### 1.1.1 `cancel_requested` 不是独立状态
|
||||||
|
|
||||||
|
`cancel_requested` **不是** `lifecycleStatus` 枚举值。它是 `AiJob.cancelRequestedAt` 字段,作为 `running` 状态上的**取消信号**而非状态迁移目标。
|
||||||
|
|
||||||
|
流程:
|
||||||
|
|
||||||
|
```
|
||||||
|
用户调用 cancel API
|
||||||
|
│
|
||||||
|
├─ lifecycleStatus = 'queued'
|
||||||
|
│ → markCancelled(jobId) → cancelled(直接终态)
|
||||||
|
│
|
||||||
|
└─ lifecycleStatus = 'running'
|
||||||
|
→ 设置 cancelRequestedAt = now()(lifecycleStatus 保持 running)
|
||||||
|
→ Worker Heartbeat / Engine 执行间隙检测到 cancelRequestedAt != null
|
||||||
|
→ 抛出 JobCancelledError
|
||||||
|
→ Engine catch → markCancelled(jobId) → cancelled
|
||||||
|
```
|
||||||
|
|
||||||
|
**设计理由**:
|
||||||
|
- 不引入中间状态 `cancel_requested` 避免状态机膨胀(5 状态 + 1 信号 vs 6 状态)
|
||||||
|
- `cancelRequestedAt` 是 `running` 上的 boolean flag,语义更轻量
|
||||||
|
- Engine 在每次 Provider 调用前后检查此字段,实现协作式取消
|
||||||
|
- §1.5 的 `STATUS_TO_LIFECYCLE` 中 `cancel_requested` 仅用于过渡期 Shadow Write(legacy `status` 列可能有此值,映射到新 `lifecycleStatus = 'cancelled'`)
|
||||||
|
|
||||||
#### 1.2 允许迁移
|
#### 1.2 允许迁移
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -367,11 +392,20 @@ export class AiJobService {
|
|||||||
async createJob(input: CreateJobInput): Promise<AiJob>;
|
async createJob(input: CreateJobInput): Promise<AiJob>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 对齐 Issue #289:事务化 AiJob 创建、Snapshot 与 Enqueue Outbox
|
||||||
interface CreateJobInput {
|
interface CreateJobInput {
|
||||||
|
/** 用户 ID */
|
||||||
userId: string;
|
userId: string;
|
||||||
|
/** Job 类型(对应 JobDefinition.jobType) */
|
||||||
jobType: string;
|
jobType: string;
|
||||||
|
/** 触发方式 */
|
||||||
|
triggerType: 'user_api' | 'admin_manual' | 'system_scheduled' | 'parent_job';
|
||||||
|
/** 分析目标类型 */
|
||||||
targetType: string;
|
targetType: string;
|
||||||
|
/** 分析目标 ID */
|
||||||
targetId: string;
|
targetId: string;
|
||||||
|
/** 父 Job ID(Job 链场景) */
|
||||||
|
parentJobId?: string;
|
||||||
/** 幂等 Key。提供时启用幂等;不提供时每次创建新 Job */
|
/** 幂等 Key。提供时启用幂等;不提供时每次创建新 Job */
|
||||||
idempotencyKey?: string;
|
idempotencyKey?: string;
|
||||||
/** 覆盖 Definition 默认值 */
|
/** 覆盖 Definition 默认值 */
|
||||||
@ -638,7 +672,16 @@ try {
|
|||||||
| Execution Engine | 内部重试循环 | `JobDefinition.execution.maxRetries` |
|
| Execution Engine | 内部重试循环 | `JobDefinition.execution.maxRetries` |
|
||||||
| Outbox | attemptCount < 3 → pending;>= 3 → dead | OutboxRepository |
|
| Outbox | attemptCount < 3 → pending;>= 3 → dead | OutboxRepository |
|
||||||
|
|
||||||
**约束**:BullMQ retry 与 Engine 内部 retry 不叠加。Engine 内部错误不抛出(不触发 BullMQ retry),而是在 Engine 内完成所有重试后,一次性 `markFailed` 或 `markSucceeded`。
|
**约束**:BullMQ retry 与 Engine 内部 retry 分工明确,不叠加。
|
||||||
|
|
||||||
|
| 层级 | 覆盖范围 | 触发条件 |
|
||||||
|
|------|---------|---------|
|
||||||
|
| **Engine 内部 retry** | 业务级错误(Provider 超时/5xx、输出校验失败) | `JobDefinition.execution.maxRetries` |
|
||||||
|
| **BullMQ retry** | 进程级故障(SIGKILL、OOM、Worker 崩溃、Redis 断连) | §3.1 `attempts` |
|
||||||
|
|
||||||
|
Engine 内部完成所有业务重试后,一次性 `markFailed` 或 `markSucceeded`。Engine 内部错误**不向 BullMQ 抛出**——BullMQ 仅看到 Worker 进程退出(SIGKILL/OOM)或未响应(stalled),此时触发 BullMQ retry,Worker 重启后从 `markFailed` 或 `markSucceeded` 的幂等语义恢复。
|
||||||
|
|
||||||
|
**这解释了 §3.1 中 `ai-interactive` attempts=2 的设计**:交互式场景只需要 2 次机会覆盖进程崩溃;业务重试已在 Engine 内部闭环。
|
||||||
|
|
||||||
#### 5.6 ValidatedOutput 与 OutputHash
|
#### 5.6 ValidatedOutput 与 OutputHash
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user