feat: add execution history queries and preserve bounded JSON payloads

This commit is contained in:
2026-09-17 14:55:23 +08:00
parent da123bba69
commit 4d4b2e9f7d
32 changed files with 1461 additions and 28 deletions

View File

@@ -88,7 +88,7 @@
外键与 `CHECK` 无法代替执行引擎。P1 已完成 HTTP 动作/队列授权、幂等摘要与原回执、受理事件,以及待执行取消的 CAS/审计事务。执行相关的以下条件继续分阶段实现:
P2 服务端已新增会话隔离、两步派发、租约、并发许可、结果回执/证据和恢复扫描,见 [执行协议](api/worker.md) 与 [阶段记录](reports/phase-2-server.md)。Worker SDK 和完整 P2 验收仍在推进。
P2 服务端已新增会话隔离、两步派发、租约、并发许可、结果回执/证据和恢复扫描,见 [执行协议](api/worker.md) 与 [阶段记录](reports/phase-2-server.md)。底层及自动 Worker SDK、尝试/证据查询已实现,完整 P2 验收仍在推进。
1. 权限验证、凭据校验、命名空间过滤和队列消费授权。
2. 同一次事务更新任务、尝试、租约、并发许可、事件与流程交付记录。
@@ -108,4 +108,6 @@ P2 服务端已新增会话隔离、两步派发、租约、并发许可、结
000002_task_api 增加任务分页索引,将业务参数、结果、回执、流程定义/输入/输出等字段改为校验过的 JSON 文本,避免原生 JSON 数字重编码。公共 Go JSON 扫描类型保持兼容,原模型职责不变。响应 DTO 与持久化模型分开;SQL 空结果先扫描到可空字节切片再转换,避免驱动与 json.RawMessage 的可空类型不兼容。
命令与验证记录见 [开发计划](08-development-plan.md) 和 [基础阶段验证报告](reports/phase-0.md)。
000004_execution_history 为已有证据表增加 `(namespace_id, attempt_id, created_at, id)` 分页索引,不新增实体或字段,不回改已有迁移。尝试列表复用执行代次唯一索引。查询 DTO 与持久化模型分离,只在详情读取业务正文,不返回执行秘密或内部摘要;接口见 [执行历史](api/execution-history.md)。
命令与验证记录见 [开发计划](08-development-plan.md)、[基础阶段验证报告](reports/phase-0.md) 与 [执行历史回归](reports/phase-2-execution-history.md)。

View File

@@ -26,7 +26,7 @@
| --- | --- | --- | --- |
| P0 基础与数据模型 | Go workspace、独立 SDK module、公共/Pulse/Weave 模型、MySQL 迁移、配置、健康检查 | 编译/竞态/静态检查;真实 MySQL 建表、隔离、唯一性、预算、不可变版本、迁移失败防护;SDK 健康调用 | 已完成并通过阶段回归(见 P0 报告) |
| P1 任务受理闭环 | 应用凭据与作用域权限、队列、幂等提交、查询、待执行取消、受理事件;SDK 客户端 | API/SDK 创建查询闭环;重复键与内容冲突、响应未确认重报、跨命名空间拒绝、参数边界 | 已完成并通过阶段回归(见 P1 报告;真实断路/提交 ACK 丢失注入留后续故障阶段) |
| P2 Worker 执行闭环 | WSS 接入、能力/容量、领取与开始、租约、续租、结果确认、排空与恢复;Worker SDK | 真 Worker 执行;失联/重连/重复确认/旧尝试拒绝;业务效果未知转核查;节点故障接管 | 开发中:服务端、SDK 协议和自动运行器通过阶段内回归;跨初始租约执行、自动重连/证据重报、有界退出及并发验证通过;尝试/证据查询、完整 Schema 和阶段验收待完成 |
| P2 Worker 执行闭环 | WSS 接入、能力/容量、领取与开始、租约、续租、结果确认、排空与恢复;Worker SDK | 真 Worker 执行;失联/重连/重复确认/旧尝试拒绝;业务效果未知转核查;节点故障接管 | 开发中:服务端、SDK 协议、自动运行器及尝试/证据 HTTP+SDK 查询通过阶段内回归;自动续租/重连、有界退出、权限/稳定分页和大载荷链路验证通过;完整 Schema 与进程级故障阶段验收待完成 |
| P3 Pulse 完整能力 | 安全重试、延时、Cron/固定间隔、漏跑策略、计划版本、并发许可、配额/背压、可靠结果订阅 | 多实例领取/触发竞争、重试上限、取消竞争、队列隔离、积压恢复、事件重复交付 | 待开发 |
| P4 Weave 主流程 | SDK 定义构建与发布校验、实例、顺序/分支/结构化并行汇合、信号/定时等待、版本绑定 | 重启接续、早到/重复信号、并行竞争、内部事件重放、发布版本兼容;端到端通用流程 | 待开发 |
| P5 Weave 恢复与查询 | 有界查询、暂停继续、取消、人工核查恢复、控制门控与审计 | 轮次与尝试独立预算;暂停/开始/回执/超时竞争;恢复保留预算;未知结果不盲目重复 | 待开发 |
@@ -47,6 +47,7 @@ SDK、文档与示例随 P1–P5 同步开发,P7 是全量核对,不是最
| 外部作业轮询 | 提交一次 → 有界查询处理中状态 → 回执或最终结果 → 超限核查 | P5 |
| 暂停与人工恢复 | 暂停 → 保存结果 → 核查/恢复 → 查看审计 | P5 |
| 故障恢复 | 节点/连接中断 → 相同身份核对 → 恢复或人工核查 | P2–P6 |
| 执行历史核对 | 读取尝试 → 查看冲突/迟到证据 → 对照权威结果 | P2,已实现完整示例 |
每个正式示例需要:前置配置、完整可运行源码、启动命令、输入、预期输出、失败路径、幂等/清理说明。SDK API 尚未实现时,文档只能标为规划,不能给出伪装可运行的代码。
@@ -76,3 +77,4 @@ SDK、文档与示例随 P1–P5 同步开发,P7 是全量核对,不是最
- [P2 服务端阶段记录](reports/phase-2-server.md)
- [P2 SDK 协议阶段记录](reports/phase-2-sdk-protocol.md)
- [P2 自动 Worker 运行器记录](reports/phase-2-worker-runtime.md)
- [P2 执行历史与大载荷记录](reports/phase-2-execution-history.md)

View File

@@ -2,7 +2,7 @@
- 文档版本:0.2
- 整理日期:2026-09-17
- 阶段:P0/P1 已完成,P2 服务端、底层 SDK 与自动 Worker 运行器已通过阶段内回归,查询/协议验收继续推进;尚未完成生产验收
- 阶段:P0/P1 已完成,P2 服务端、底层 SDK、自动 Worker 运行器及执行历史查询已通过阶段内回归,协议与进程故障验收继续推进;尚未完成生产验收
- 适用范围:Orbit 统一平台,包含 Pulse 任务调度模块、Weave 流程编排模块与公共能力。平台面向多个业务系统复用。
## 阅读顺序

View File

@@ -9,6 +9,8 @@
| `GET /health/live` | 已实现 | [健康检查](health.md) |
| `GET /health/ready` | 已实现,仅验证数据库与迁移记录 | [健康检查](health.md) |
| `/v1/tasks` 提交、查询、分页与待执行取消 | P1 已实现 | [任务接口](tasks.md) |
| `/v1/tasks/{task_id}/attempts` 与尝试详情 | P2 已实现 | [执行历史](execution-history.md) |
| `/v1/tasks/{task_id}/attempts/{attempt_id}/evidence` 与证据详情 | P2 已实现 | [执行历史](execution-history.md) |
| `/v1/queues` 创建与查询 | P1 已实现 | [队列接口](queues.md) |
| 凭据校验与初始化 CLI | P1 已实现 | [鉴权](authentication.md) |
| `/v1/worker/connect` | P2 服务端、底层 SDK 与自动 Worker 已实现;完整阶段验收继续推进 | [Worker 契约](worker.md) |

View File

@@ -0,0 +1,166 @@
# 执行尝试与证据查询 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)。

View File

@@ -1,8 +1,8 @@
# 任务接口 v1
状态:P1 已实现并通过真实 MySQL 与 SDK 回归。当前提供受理、查询、分页和待执行取消;Worker 执行与自动重试在 P2–P3 实现。
状态:P1 已实现并通过真实 MySQL 与 SDK 回归。当前提供受理、查询、分页和待执行取消;P2 已提供 Worker 执行与历史查询,策略重试在 P3 实现。
P2 进展:服务端执行内核和 WSS 已可产生 LEASED、RUNNING、SUCCEEDED、FAILED、NEEDS_REVIEW 等状态,见 [Worker 契约](worker.md);独立 Worker SDK 仍在开发,自动策略重试尚未完成。
P2 进展:服务端执行内核、WSS 与独立自动 Worker SDK 已可产生 LEASED、RUNNING、SUCCEEDED、FAILED、NEEDS_REVIEW 等状态,见 [Worker 契约](worker.md);[尝试与证据查询](execution-history.md) 可核对每次执行,自动策略重试尚未完成。
## 公共约定
@@ -28,7 +28,7 @@ P2 进展:服务端执行内核和 WSS 已可产生 LEASED、RUNNING、SUCCEED
| start_deadline_at | time / null | 无独立限制 | 必须晚于当前时间,不早于 available_at,不晚于总截止时间 |
| task_timeout_ms | uint64 | 0 或省略为 86400000 | 从受理时计算的总时限,最大 30 天(2592000000 毫秒) |
| recovery_safety | string | RECONCILE_ONLY | 也可为 IDEMPOTENT;必须基于处理器真实的幂等能力声明 |
| retry | object | 见下表 | 受理时冻结的执行策略;当前阶段仅保存 |
| retry | object | 见下表 | 受理时冻结策略;P2 已执行尝试预算及时限,策略退避重试在 P3 实现 |
处理器及版本名称以 ASCII 字母或数字开头,后续只能包含字母、数字、`_ . : -`。时间年份为 2000–9998。
@@ -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"}}
```
批量受理、执行历史、人工重试和运行中取消尚未实现。完整可运行程序见 [SDK 任务示例](../../sdk/go/examples/tasks/main.go),已验证异常场景见 [P1 回归报告](../reports/phase-1.md)。SDK 忽略未知响应字段;更改已有字段语义需升级契约和回归。
批量受理、人工重试和运行中取消尚未实现。[执行历史](execution-history.md) 已提供尝试与证据的列表和详情。完整可运行程序见 [SDK 任务示例](../../sdk/go/examples/tasks/main.go),已验证异常场景见 [P1 回归报告](../reports/phase-1.md)。SDK 忽略未知响应字段;更改已有字段语义需升级契约和回归。

View File

@@ -1,6 +1,6 @@
# Worker 通信与执行契约 v1(开发中)
已实现服务端执行事务、WebSocket 接入、[独立 Go 底层协议 SDK](../sdk/worker.md) 和 [自动 Worker 运行器](../sdk/worker-runtime.md),通过真实 WSS、自动续租、ACK 丢失/持续断网恢复及有界退出回归。**P2 尚未完成**:尝试/证据查询、完整协议 Schema 与完整阶段验收继续推进。底层 WorkerConnection 不自动管理处理器;NewWorker / Run 提供自动管理。
已实现服务端执行事务、WebSocket 接入、[独立 Go 底层协议 SDK](../sdk/worker.md)、[自动 Worker 运行器](../sdk/worker-runtime.md) 与 [尝试/证据查询](execution-history.md),通过真实 WSS、自动续租、ACK 丢失/持续断网恢复、有界退出及历史权限/分页回归。**P2 尚未完成**:完整协议 Schema 与完整阶段验收继续推进。底层 WorkerConnection 不自动管理处理器;NewWorker / Run 提供自动管理。
## 1. 接入与身份

View File

@@ -36,11 +36,20 @@
- 异常:自动心跳/续租与原身份重连;普通错误/panic 按未知效果报告,超时退出不声称杀死 goroutine;完整故障证据见 [回归记录](../reports/phase-2-worker-runtime.md)。
- 清理:正常排空关闭连接,保留历史;进程被强杀后的在途状态由租约恢复与核查衔接。
## 已可运行:执行历史与冲突证据核对
- 源码:[执行历史示例](../../sdk/go/examples/history/main.go),[启动命令和输入输出](../sdk/README.md#6-查询执行历史与证据)。
- 前置:迁移到当前版本、启动服务,专用凭据具备提交/读取与 Worker 权限。
- 步骤:创建模拟任务 → 开始授权 → 保存 v1 结果 → 用另一消息身份报告 v2 → 查询尝试/证据列表与详情 → 核对任务仍保留 v1。
- 预期:SUCCEEDED、attempts=1、evidence=1、reason=RESULT_CONFLICT、disposition=EVIDENCE_ONLY;实际结果中的大整数保持精确。
- 异常:迟到或矛盾内容不能覆盖权威结果;缺少动作权限返回 403,错配父资源、跨命名空间或队列越权返回 404,详见 [接口](../api/execution-history.md)。示例不调用外部业务系统。
- 清理:正常结束确认排空并关闭连接;任务及证据保留用于追踪,不硬删除。重复运行创建独立任务。
## 计划场景与验收标准
| 场景 | 输入与步骤 | 预期结果 | 必测异常 | 状态 |
| --- | --- | --- | --- | --- |
| 文件转换 | 对象引用 → 提交任务 → Worker 转换 → 结果引用 | 同一操作获得一次业务结果,历史可查 | 重复提交、Worker 在结果上报前中断 | P1 受理完成,P2 执行待开发 |
| 文件转换 | 对象引用 → 提交任务 → Worker 转换 → 结果引用 | 同一操作获得一次业务结果,历史可查 | 重复提交、Worker 在结果上报前中断 | 受理与执行框架已实现,实际转换示例待补齐 |
| 定期同步 | 发布计划 → 周期触发 → 暂停 → 恢复 | 触发身份唯一,漏跑策略可追溯 | 多节点竞争、停机后补跑上限 | P3 待开发 |
| 并行生成 | 输入对象 → 并行计算两份结果 → 汇合 | 两支满足条件后只创建一份后继工作 | 一支失败、重复结果、汇合竞争 | P4 待开发 |
| 等待审核 | 校验 → 等待信号 → 发布结果 | 只接受授权、匹配当前操作的信号 | 早到、重复、过期与越权信号 | P4 待开发 |

View File

@@ -0,0 +1,55 @@
# P2 执行历史与大载荷回归
日期:2026-09-17。本轮完成尝试及证据查询,P2 的完整 WS Schema 与进程级故障阶段验收仍待完成。接口与 SDK 模型均提供中文职责和字段注释。
## 实现范围
- 四个 HTTP GET 与对应独立 Go SDK 方法:尝试列表/详情、证据列表/详情。
- 每次请求重新校验凭据、命名空间、tasks:read、队列范围及父子关系;详情不暴露执行秘密或内部摘要。
- 列表省略业务正文,以执行代次或时间/ID 稳定分页;详情提供原结果和证据内容,两者分开。
- 新增 000004 前向迁移,为证据查询增加四列索引;既有迁移不变,仍为 32 个持久化模型。
- 新增可运行 `examples/history`,演示矛盾回报被保留为证据而不覆盖权威结果。
完整接口、字段、错误码和 SDK 对应方法见 [执行历史](../api/execution-history.md),运行步骤见 [SDK 手册](../sdk/README.md#6-查询执行历史与证据)。
## 修复与验证过程
大载荷回归发现默认 JSON HTML 转义会将合法的约 240 KiB `<>&` 文本放大至约 1.4 MiB,超出 HTTP/WS 限制。服务端 JSON 响应、WS 帧、提交幂等回执与 SDK 传输现在使用关闭 HTML 转义的编码器;仍使用 JSON 通道,不允许把结果直接嵌入 HTML。没有放宽消息上限,没有改变幂等语义摘要算法或重写历史数据。
首轮新测试还发现测试用例重复使用解码结构而残留被省略的字段,已改为每页新建结果;随后真实 MySQL 捕获尝试详情 JOIN 错用了 Worker 实例列名,已修复为实际表字段。修复后完整集成脚本重跑通过,没有跳过失败项。
## 环境与入口
macOS arm64、Go 1.27.1、Docker MySQL 8.4.10,WS 依赖锁定 coder/websocket v1.8.15。数据库使用随机凭据和回环随机端口,结束删除临时容器。真实 Orbit 进程提供 HTTP/WS,已有 WSS 故障回归使用受信任测试证书。
```sh
make test
make vet
make build
make integration
cd sdk/go
GOWORK=off go test -race ./...
GOWORK=off go vet ./...
```
## 本轮通过的回归
| 场景 | 实际验证 |
| --- | --- |
| 执行尝试历史 | 同一任务第一次未开始即过期,第二次获批并成功;逆序分页、次数、时间、归属和精确结果正确 |
| 追加证据及去重 | 未开始报告保留 NOT_STARTED;成功后矛盾内容保留 RESULT_CONFLICT,同消息重报只出现一次 |
| 同时间戳分页 | 一条 SQL 插入同微秒的两条受控证据,逐条翻页无重复或遗漏 |
| 访问控制 | 四个路由覆盖跨命名空间、队列越权和错配父资源;缺失动作权限 403、撤销凭据 401;不返回秘密和摘要 |
| 输入边界 | 非法/过长游标、跨任务/尝试/类型复用、重复/未知查询参数、错误编码、非法 ID 和分页上限被拒绝 |
| 列表与详情 | 空 items 为 [];摘要不含 result/payload;详情不丢失超过 2^53 的整数或高精度小数 |
| 真实大载荷链路 | 约 240 KiB `<>&` JSON 经提交、同键重复回执、WS 派发、开始、结果上报、详情与冲突证据读取保持内容;任务完整输入+结果仍在 SDK 响应限制内 |
| SDK 契约 | 四个 GET 路径、授权头、URL 编码、uint64 字符串、精确 RawMessage 和本地参数拒绝;独立 module 不引用服务端 |
| 迁移 | 全部迁移应用成功,证据索引四列实际存在;既有约束/不可变证据/迁移校验回归继续通过 |
| 既有链路 | 模型、任务事务、Worker、WSS、自动续租、ACK 丢失与断网恢复、有界退出和并发回归全部通过 |
| 命令行示例 | 健康、任务受理、底层 Worker、自动 Worker、执行历史五个例子均在真实服务上运行通过 |
## 当前边界
查询是当前快照,不是跨页一致快照或完整事件/审计导出。尝试详情显示当前/最后归属会话,不重建全部归属历史。只读结果不授予执行权,EVIDENCE_ONLY 不构成人工裁定。
本轮没有完成旧数据转义重编码迁移、策略重试、人工恢复、运行中取消、可靠事件订阅、数据库故障转移或容量测试。大载荷测试使用真实 WS,已有 WSS 回归另外覆盖 TLS 和故障恢复;不将这些结果描述为多主机生产高可用验收。下一步继续 P2 协议 Schema 与进程级故障验收。

View File

@@ -1,6 +1,6 @@
# Go SDK 接入说明
已实现健康查询、任务提交/查询/分页/待执行取消、队列创建/查询、[自动 Worker](worker-runtime.md) 和 [Worker 底层协议 SDK](worker.md)。流程构建等后续接口按 [开发计划](../08-development-plan.md) 继续实现。
已实现健康查询、任务提交/查询/分页/待执行取消、队列创建/查询、[自动 Worker](worker-runtime.md)、[Worker 底层协议 SDK](worker.md) 和 [执行历史查询](../api/execution-history.md)。流程构建等后续接口按 [开发计划](../08-development-plan.md) 继续实现。
module:`git.yuntuo.hk/k2safe/orbit/sdk/go`。SDK 使用独立 go.mod,依赖 Go 标准库与 `github.com/coder/websocket v1.8.15`,不引用服务端模型或数据库实现。
@@ -112,6 +112,10 @@ fmt.Println(cancelled.Task.State)
| CancelTask | taskID、key、CancelTaskRequest / CancelTaskResult | [任务](../api/tasks.md) |
| CreateQueue | key、CreateQueueRequest / CreateQueueResult | [队列](../api/queues.md) |
| GetQueue | queueID / Queue | [队列](../api/queues.md) |
| ListTaskAttempts | taskID、HistoryPageRequest / AttemptPage | [执行历史](../api/execution-history.md) |
| GetTaskAttempt | taskID、attemptID / Attempt | [执行历史](../api/execution-history.md) |
| ListAttemptEvidence | taskID、attemptID、HistoryPageRequest / AttemptEvidencePage | [执行历史](../api/execution-history.md) |
| GetAttemptEvidence | taskID、attemptID、evidenceID / AttemptEvidence | [执行历史](../api/execution-history.md) |
所有方法第一个参数为 context.Context,返回值之外都返回 error。命令方法要求调用方提供稳定 key,不自动生成或重试。ListTasksRequest 接受 QueueID、State、Limit、Cursor。
@@ -131,6 +135,45 @@ go mod tidy
将示例路径换成真实路径,不要把本机绝对路径作为发布依赖提交。后续会验证独立 module 标签和真实远端取包,再提供 go get 发布命令。当前源码同时验证 GOWORK=off 的独立构建。
## 6. 后续交付
## 6. 查询执行历史与证据
P2 已提供底层协议与 [自动 Worker 运行器及示例](worker-runtime.md),继续补齐查询与阶段验收;P3 提供计划与结果订阅;P4–P5 提供流程构建发布、信号、等待、轮询与人工恢复。每项随实现同步交付可运行示例及异常回归。
只读凭据需要 tasks:read 和任务所属队列范围。下方为接入函数片段,遍历尝试摘要并查询每条尝试详情;每次页面请求均需检查错误:
```go
pageRequest := orbit.HistoryPageRequest{Limit: 20}
for {
page, err := client.ListTaskAttempts(ctx, taskID, pageRequest)
if err != nil { return err }
for _, summary := range page.Items {
detail, err := client.GetTaskAttempt(ctx, taskID, summary.ID)
if err != nil { return err }
fmt.Println(detail.ID, detail.Epoch, detail.State)
// Result 是 json.RawMessage;读取业务字段时保留精确类型。
}
if page.NextCursor == "" { break }
pageRequest.Cursor = page.NextCursor
}
```
查询证据对应 `ListAttemptEvidence(ctx, taskID, attemptID, pageRequest)` 与 `GetAttemptEvidence(ctx, taskID, attemptID, evidenceID)`,列表相同方式使用 NextCursor。结果正文只在详情返回,列表适合按需展示。查询快照不授予执行权;证据的 outcome 是 Worker 原始声明,EVIDENCE_ONLY 不能当作任务成功。当前权威任务结果用 GetTask 核对。
完整 [执行历史示例](../../sdk/go/examples/history/main.go) 会创建一条模拟任务,提交固定成功结果,再模拟矛盾报告,并通过上述四个查询核对历史。先按 [Worker 初始化步骤](worker.md#1-可运行的文本规范化示例) 准备具有提交、读取及 Worker 权限的专用凭据,再从仓库根目录执行:
```sh
cd sdk/go
ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../../.local/worker.credentials.json \
go run ./examples/history
```
预期输出:
```text
task=<任务ID> state=SUCCEEDED attempts=1 evidence=1 reason=RESULT_CONFLICT disposition=EVIDENCE_ONLY
```
示例是受控故障演示,不调用外部业务系统。原结果为 `{"version":"v1","sequence":9007199254740993}`,矛盾内容 `{"version":"v2"}` 只进入证据;任务仍保留原成功结果。每次运行创建独立任务/处理器身份,正常结束会排空并关闭连接,历史保留。示例不自动处理全部网络故障,失败时非零退出;应按输出的稳定错误分类核查,持续消费请使用自动 Worker。
## 7. 后续交付
P2 已提供底层协议、[自动 Worker 运行器及示例](worker-runtime.md) 与历史查询,继续补齐协议 Schema 及阶段验收;P3 提供计划与结果订阅;P4–P5 提供流程构建发布、信号、等待、轮询与人工恢复。每项随实现同步交付可运行示例及异常回归。

View File

@@ -1,6 +1,6 @@
# 自动 Worker 接入
更新:2026-09-17。自动 Worker 已实现,并通过真实 MySQL、实际服务命令、WSS 断线/ACK 丢失/持续断网回归。P2 的尝试与证据查询、完整协议 Schema 和进程级故障验收仍需继续完成。
更新:2026-09-17。自动 Worker 已实现,并通过真实 MySQL、实际服务命令、WSS 断线/ACK 丢失/持续断网回归。[尝试与证据查询](../api/execution-history.md) 已可用于核对结果;P2 的完整协议 Schema 和进程级故障验收仍需继续完成。
源码:[运行器](../../sdk/go/worker_runtime.go)、[配置与中文注释](../../sdk/go/worker_runtime_types.go)、[完整示例](../../sdk/go/examples/worker/main.go)。特殊传输集成可以使用 [底层协议 SDK](worker.md),普通消费直接使用本页的 Worker。