167 lines
9.2 KiB
Markdown
167 lines
9.2 KiB
Markdown
# 执行尝试与证据查询 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)。
|