Files
orbit/docs/api/execution-history.md

167 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 执行尝试与证据查询 v1
更新:2026-09-17。四个只读接口及独立 Go SDK 已实现;对应 [可运行示例](../../sdk/go/examples/history/main.go) 和 [回归记录](../reports/phase-2-execution-history.md)。
## 1. 用途与权限
任务代表一次受理的工作,尝试代表其中一次执行代次。领取后未获开始授权就过期的尝试也会保留,并消耗尝试预算。重连恢复同一次尝试,不创建新的尝试记录。
证据保存 Worker 的迟到、未开始或冲突报告。`outcome=SUCCEEDED` 只是原报告的声明;`disposition=EVIDENCE_ONLY` 表示采集时仅作为证据保存,不能解释为任务成功。权威任务状态与结果使用 [GetTask](tasks.md) 查询。当前接口不执行人工裁定、恢复或重试。
四个接口均要求 `Authorization: Bearer <token>`、`tasks:read` 动作及任务所属队列范围。凭据确定命名空间,每次调用都重新校验有效性。ID 是 32 位小写十六进制字符串,全部父子关系都校验;知道尝试 ID 或证据 ID 不代表有权读取。
响应为 `application/json`,含 `Cache-Control: no-store`、`X-Content-Type-Options: nosniff`;追踪 ID 同时出现在 `X-Request-ID` 和正文 `request_id`。这些 JSON 供解析使用,不能直接嵌入 HTML。SDK 保留结果中的数字文本,不先转换为 float64。
## 2. 请求与分页
| 方法和路径 | data 对象 | SDK 方法 |
| --- | --- | --- |
| `GET /v1/tasks/{task_id}/attempts` | AttemptPage | `ListTaskAttempts(ctx, taskID, page)` |
| `GET /v1/tasks/{task_id}/attempts/{attempt_id}` | Attempt | `GetTaskAttempt(ctx, taskID, attemptID)` |
| `GET /v1/tasks/{task_id}/attempts/{attempt_id}/evidence` | AttemptEvidencePage | `ListAttemptEvidence(ctx, taskID, attemptID, page)` |
| `GET /v1/tasks/{task_id}/attempts/{attempt_id}/evidence/{evidence_id}` | AttemptEvidence | `GetAttemptEvidence(ctx, taskID, attemptID, evidenceID)` |
没有请求体,不需要 Idempotency-Key。仅两个列表接受查询参数:
| 参数 | 类型 / 默认 | 限制 |
| --- | --- | --- |
| limit | 整数,默认 20 | 1–100;SDK 的 0 表示不传、采用默认值,HTTP 显式 0 被拒绝 |
| cursor | 字符串,默认空 | 最长 1024 字节;原样使用前一页的 next_cursor,并进行 URL 编码 |
参数只能出现一次;未知字段、重复参数、错误 URL 编码、非法游标均返回 400。详情接口不接受查询参数。游标绑定命名空间、任务、尝试和列表类型,不能跨资源复用,也不能作为授权证明。
尝试按 `epoch DESC`,证据按 `(created_at DESC, id DESC)` 分页,相同微秒时间以 ID 区分。使用索引和位置条件,不使用 offset 或全量 count。`items` 始终为数组,空时为 `[]`;没有下一页时省略 next_cursor。列表不带业务结果正文。
分页不承诺跨请求快照。读取期间尝试状态可能更新、可能出现新记录;刷新最新记录应从空游标重新读取。limit 可以调整,父资源不可改变。
```sh
curl --get "$ORBIT_URL/v1/tasks/$TASK_ID/attempts" \
-H "Authorization: Bearer $ORBIT_TOKEN" --data-urlencode 'limit=20'
curl "$ORBIT_URL/v1/tasks/$TASK_ID/attempts/$ATTEMPT_ID" \
-H "Authorization: Bearer $ORBIT_TOKEN"
curl --get "$ORBIT_URL/v1/tasks/$TASK_ID/attempts/$ATTEMPT_ID/evidence" \
-H "Authorization: Bearer $ORBIT_TOKEN" \
--data-urlencode 'limit=20' --data-urlencode "cursor=$CURSOR"
curl "$ORBIT_URL/v1/tasks/$TASK_ID/attempts/$ATTEMPT_ID/evidence/$EVIDENCE_ID" \
-H "Authorization: Bearer $ORBIT_TOKEN"
```
变量使用实际资源 ID,首次证据查询的 CURSOR 设为空。成功均为 HTTP 200;响应信封见下方完整示例,ID 和时间为示意值。
## 3. 尝试字段与响应
| 字段 | 类型 / 是否始终返回 | 含义 |
| --- | --- | --- |
| id、task_id | string / 是 | 尝试与父任务标识 |
| epoch | 十进制字符串 / 是 | 单任务执行代次;SDK uint64 |
| state | string / 是 | LEASED、RUNNING、SUCCEEDED、FAILED、CANCELLED、EXPIRED、UNKNOWN;枚举不表示全部状态转换已实现 |
| revision | 十进制字符串 / 是 | 记录版本,续租及归属变化可递增;SDK uint64 |
| lease_until | UTC RFC 3339 / 是 | 数据库记录的租约期限,**查询不提供执行授权** |
| authorized_at | UTC RFC 3339 / 否 | 获批开始时间;省略表示尚未获批,不证明外部效果是否发生 |
| ended_at | UTC RFC 3339 / 否 | 尝试结束时间;尚未结束时省略 |
| error_code | string / 否 | 稳定错误分类,无错误时省略 |
| created_at、updated_at | UTC RFC 3339 / 是 | 创建和最近更新时间,最多微秒精度 |
| session_id、worker_instance_id | string / 仅详情 | 当前或最后归属会话及进程身份;会话可能因恢复改变,不是完整归属变更日志 |
| result | JSON / 仅详情,可省略 | 此尝试已保存的结果;无结果时省略,与追加证据分开 |
列表响应:
```json
{
"request_id":"44444444444444444444444444444444",
"data":{"items":[{
"id":"22222222222222222222222222222222",
"task_id":"11111111111111111111111111111111",
"epoch":"1","state":"SUCCEEDED","revision":"3",
"lease_until":"2026-09-17T08:00:30Z",
"authorized_at":"2026-09-17T08:00:01Z","ended_at":"2026-09-17T08:00:02Z",
"created_at":"2026-09-17T08:00:00Z","updated_at":"2026-09-17T08:00:02Z"
}]}
}
```
详情响应为展开对象:
```json
{
"request_id":"44444444444444444444444444444444",
"data":{
"id":"22222222222222222222222222222222",
"task_id":"11111111111111111111111111111111",
"epoch":"1","state":"SUCCEEDED","revision":"3",
"lease_until":"2026-09-17T08:00:30Z",
"authorized_at":"2026-09-17T08:00:01Z","ended_at":"2026-09-17T08:00:02Z",
"created_at":"2026-09-17T08:00:00Z","updated_at":"2026-09-17T08:00:02Z",
"session_id":"33333333333333333333333333333333",
"worker_instance_id":"55555555555555555555555555555555",
"result":{"version":"v1","sequence":9007199254740993}
}
}
```
不返回 lease_secret、instance_secret、凭据或内部摘要。执行权限必须经过 [Worker 开始/恢复与当前租约确认](worker.md),不能通过历史详情推导。
## 4. 证据字段与响应
| 字段 | 类型 / 是否始终返回 | 含义 |
| --- | --- | --- |
| id、task_id、attempt_id | string / 是 | 证据及已校验的父资源标识 |
| outcome | string / 是 | 原报告的 SUCCEEDED、FAILED 或 UNKNOWN |
| error_code | string / 否 | 原报告的错误分类,空时省略 |
| reason | string / 是 | LEASE_LOST(授权失效)、NOT_STARTED(未获批开始)、RESULT_CONFLICT(与已保存结果冲突) |
| disposition | string / 是 | 固定 EVIDENCE_ONLY,描述采集处理方式 |
| created_at | UTC RFC 3339 / 是 | 首次保存时间,相同身份的重复报告不刷新 |
| message_id | string / 仅详情 | 原报告身份,便于追踪同一次重报 |
| payload | JSON / 仅详情 | 原报告结果或证据引用,最大 256 KiB,保留精确数字文本 |
列表响应:
```json
{
"request_id":"44444444444444444444444444444444",
"data":{"items":[{
"id":"66666666666666666666666666666666",
"task_id":"11111111111111111111111111111111",
"attempt_id":"22222222222222222222222222222222",
"outcome":"SUCCEEDED","reason":"RESULT_CONFLICT","disposition":"EVIDENCE_ONLY",
"created_at":"2026-09-17T08:00:03Z"
}]}
}
```
详情响应:
```json
{
"request_id":"44444444444444444444444444444444",
"data":{
"id":"66666666666666666666666666666666",
"task_id":"11111111111111111111111111111111",
"attempt_id":"22222222222222222222222222222222",
"outcome":"SUCCEEDED","reason":"RESULT_CONFLICT","disposition":"EVIDENCE_ONLY",
"created_at":"2026-09-17T08:00:03Z",
"message_id":"77777777777777777777777777777777","payload":{"version":"v2"}
}
}
```
保存 v2 证据不会覆盖尝试中的 v1 结果。查询没有状态变更或去重写入;人工裁定、证据采纳与审计管理属于后续能力。
## 5. 错误、超时与兼容
| HTTP / code | 处理 |
| --- | --- |
| 400 INVALID_ARGUMENT | 修正 ID、limit、游标及查询参数;不可盲目重试 |
| 401 UNAUTHENTICATED | 核对凭据撤销/到期、应用及命名空间状态 |
| 403 PERMISSION_DENIED | 凭据缺少 tasks:read |
| 404 NOT_FOUND | 资源不存在、父子不匹配、跨命名空间或不在队列范围内;不区分具体原因 |
| 503 UNAVAILABLE | 只读查询失败,可在总体截止内有限退避重试 |
```json
{"request_id":"44444444444444444444444444444444","error":{"code":"NOT_FOUND","message":"resource not found"}}
```
服务端操作期限 8 秒;SDK 默认 HTTP 超时 10 秒,可用 context 缩短。SDK 不自动重试查询;取消查询不取消任务。SDK 业务响应上限 1 MiB,列表通过省略大正文和最多 100 条保持有界。每次重读获得当次数据,不保证与前次完全相同。
当前开发契约为 v1,SDK 尚未发布版本,接入方式见 [SDK 手册](../sdk/README.md)。SDK 忽略新增响应字段;已有字段含义改变需升级契约并回归。跨租户/队列、父子错配、重复证据、同时间戳分页、精确数字和大载荷均有实际回归,见 [验证记录](../reports/phase-2-execution-history.md)。