feat: add durable safe retries with uncertainty tracking and SDK examples

This commit is contained in:
2026-09-17 15:43:44 +08:00
parent 9e3d4be5cc
commit d65cf96ea7
44 changed files with 1300 additions and 77 deletions

View File

@@ -1,8 +1,8 @@
# 任务接口 v1
状态:P1 已实现并通过真实 MySQL 与 SDK 回归。当前提供受理、查询、分页和待执行取消;P2 已提供 Worker 执行与历史查询,策略重试在 P3 实现。
状态:P1 已实现并通过真实 MySQL 与 SDK 回归。当前提供受理、查询、分页和待执行取消;P2 已提供 Worker 执行与历史查询,P3 已接入 [安全重试](retries.md)。
P2 进展:服务端执行内核、WSS 与独立自动 Worker SDK 已可产生 LEASED、RUNNING、SUCCEEDED、FAILED、NEEDS_REVIEW 等状态,见 [Worker 契约](worker.md);[尝试与证据查询](execution-history.md) 可核对每次执行,自动策略重试尚未完成。
P2 进展:服务端执行内核、WSS 与独立自动 Worker SDK 已可产生 LEASED、RUNNING、SUCCEEDED、FAILED、NEEDS_REVIEW 等状态,见 [Worker 契约](worker.md);[尝试与证据查询](execution-history.md) 可核对每次执行;重试以冻结策略、明确失败分类及未知效果安全声明为依据。
## 公共约定
@@ -28,7 +28,7 @@ P2 进展:服务端执行内核、WSS 与独立自动 Worker SDK 已可产生
| start_deadline_at | time / null | 无独立限制 | 必须晚于当前时间,不早于 available_at,不晚于总截止时间 |
| task_timeout_ms | uint64 | 0 或省略为 86400000 | 从受理时计算的总时限,最大 30 天(2592000000 毫秒) |
| recovery_safety | string | RECONCILE_ONLY | 也可为 IDEMPOTENT;必须基于处理器真实的幂等能力声明 |
| retry | object | 见下表 | 受理时冻结策略;P2 已执行尝试预算及时限,策略退避重试在 P3 实现 |
| retry | object | 见下表 | 受理时冻结策略;包含首次领取的有限尝试、退避及每次时限,见 [安全重试](retries.md) |
处理器及版本名称以 ASCII 字母或数字开头,后续只能包含字母、数字、`_ . : -`。时间年份为 2000–9998。
@@ -90,7 +90,7 @@ curl -i "$ORBIT_URL/v1/tasks" \
}
```
可选响应字段:start_deadline_at、result、cancel_requested_at、completed_at、business_key,未设置时省略。终态有 completed_at。状态集合为 WAITING / LEASED / RUNNING / NEEDS_REVIEW / SUCCEEDED / FAILED / CANCELLED;P1 仅主动产生 WAITING 和 CANCELLED。
可选响应字段:start_deadline_at、result、cancel_requested_at、completed_at、business_key,未设置时省略。effect_uncertain=true 表示存在尚未核实的授权执行效果,false 时省略;详情、摘要和 Worker 派发均可返回。等待重试时 result/completed_at 省略,历史结果在尝试中保留。终态有 completed_at。状态集合为 WAITING / LEASED / RUNNING / NEEDS_REVIEW / SUCCEEDED / FAILED / CANCELLED;P1 仅主动产生 WAITING 和 CANCELLED。
### 幂等与失败处理
@@ -164,7 +164,7 @@ curl "$ORBIT_URL/v1/tasks/$TASK_ID:cancel" \
expected_revision 必填,为非零 uint64 的十进制字符串;reason 必填且不能全为空白,最多 1024 个 Unicode 字符。服务端以版本和状态条件更新,只有一个竞争请求能成功。
200 的 data 为 `{"task":<完整最新任务>,"deduplicated":false}`。示例任务会变为 state=CANCELLED、revision="2",写入 cancel_requested_at/completed_at,并同事务追加取消事件及审计。首次取消之后使用相同键、原因和**原 expected_revision**重报,返回原取消回执且 deduplicated=true。换键重报已取消任务返回 409。
200 的 data 为 `{"task":<完整最新任务>,"deduplicated":false}`。示例任务会变为 state=CANCELLED、revision="2",写入 cancel_requested_at/completed_at,并同事务追加取消事件及审计。首次取消之后使用相同键、原因和**原 expected_revision**重报,返回原取消回执且 deduplicated=true。换键重报已取消任务返回 409。若 WAITING 来自未知效果后的自动重试,取消会保存 cancel_requested_at 并转 NEEDS_REVIEW,保留 effect_uncertain=true、completed_at 为空,停止后续尝试但不宣称此前效果已经撤销。
SDK:`Client.CancelTask(ctx, taskID, key, request)`。此操作不承诺回滚任何已发生的外部业务效果。
@@ -186,4 +186,4 @@ SDK:`Client.CancelTask(ctx, taskID, key, request)`。此操作不承诺回滚
{"request_id":"44444444444444444444444444444444","error":{"code":"IDEMPOTENCY_CONFLICT","message":"idempotency key was used with different content"}}
```
批量受理、人工重试和运行中取消尚未实现。[执行历史](execution-history.md) 已提供尝试与证据的列表和详情。完整可运行程序见 [SDK 任务示例](../../sdk/go/examples/tasks/main.go),已验证异常场景见 [P1 回归报告](../reports/phase-1.md)。SDK 忽略未知响应字段;更改已有字段语义需升级契约和回归。
有限自动重试已实现,具体分类、退避、回执和升级边界见 [安全重试](retries.md)。批量受理、人工重试和运行中取消尚未实现。[执行历史](execution-history.md) 已提供尝试与证据的列表和详情。完整可运行程序见 [SDK 任务示例](../../sdk/go/examples/tasks/main.go),已验证异常场景见 [P1 回归报告](../reports/phase-1.md)。SDK 忽略未知响应字段;更改已有字段语义需升级契约和回归。