feat: add scoped task source tracing and SDK examples

This commit is contained in:
2026-09-17 22:40:42 +08:00
parent 7641423f9d
commit 2b8213a4f7
26 changed files with 760 additions and 9 deletions

View File

@@ -1,6 +1,6 @@
# Orbit 功能说明:Pulse 与公共能力
> 版本 0.2 · 2026-09-17。Pulse 与 Weave 首版功能范围已确认;标注“建议”的细节待评审。Weave 具体范围另见流程设计。基础、任务执行、调度、资源控制和可靠订阅已实现;批量受理、独立任务核查/人工重试及业务键/创建时间查询已实现,事务Outbox接入等继续开发,实现状态见持续开发计划。
> 版本 0.2 · 2026-09-17。Pulse 与 Weave 首版功能范围已确认;标注“建议”的细节待评审。Weave 具体范围另见流程设计。基础、任务执行、调度、资源控制和可靠订阅已实现;批量受理、独立任务核查/人工重试、业务键/创建时间查询及直接来源追踪已实现,事务Outbox接入等继续开发,实现状态见持续开发计划。
## 1. 目标与责任边界

View File

@@ -174,3 +174,7 @@ P2 服务端已新增会话隔离、两步派发、租约、并发许可、结
BusinessKey沿用既有可空VARCHAR(191),Go/SQL中文注释明确精确匹配、区分大小写和尾部空格;排序规则显式utf8mb4_0900_bin,历史文本原样保留,不增加模型字段。新增(namespace_id,queue_id,business_key,created_at,id)及增加state的组合索引,配合原两种创建时间索引覆盖有无状态/业务键的四种查询。
HTTP/SDK创建时间范围使用包含下界、不包含上界;v2游标以固定长度摘要绑定全部规范化筛选,当前权限逐页校验。单项提交、计划生成和人工重试仅把Go空字符串映射为NULL,不用连接排序规则折叠空格。仍为35个实体、289个中文注释字段,无外键/级联;具体接口与升级边界见[查询手册](api/task-queries.md)。
### 任务直接来源视图
[来源查询](api/task-source.md)复用Task.OwnerKind/OwnerID/RetryOf、Schedule、ScheduleVersion与ScheduleOccurrence,沿已有(namespace_id,task_id)唯一索引及计划版本键定位,不增加表、持久化字段、索引或迁移。只读响应模型的每个字段也有中文注释。任务、计划、触发版本与队列归属在认证事务中显式验证,缺失关联不被默认为普通任务;流程来源随Weave实现。

View File

@@ -27,7 +27,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 验收报告 |
| P3 Pulse 完整能力 | 安全重试、延时、Cron/固定间隔、漏跑策略、计划版本、运行中取消、并发许可、配额/背压、可靠结果订阅、批量受理、独立任务核查/人工重试、查询筛选与事务Outbox接入 | 多实例领取/触发竞争、重试上限、取消竞争、队列隔离、积压恢复、事件重复交付 | 进行中:安全重试、计划调度、运行中取消、队列控制/限速/积压背压、跨命名空间应用配额、显式资源键许可及 SDK 场景已实现并通过全量回归;优先级及节点公平派发已实现并通过全量回归;可靠订阅核心、HTTP/WSS、管理 SDK 和管理示例已实现并回归;消费 SDK、协议示例及两项节点强杀回归已完成;业务 Inbox 场景、COMMIT响应丢失及消费者进程故障回归已完成;批量受理、SDK、接口与部分补交示例已完成全量回归;独立任务核查/人工重试、审计查询、两次真实HTTP回执丢失及完整示例已通过全量回归;业务键/创建时间筛选、SDK与示例已通过全量回归;任务详情来源追踪与事务Outbox接入待完成 |
| P3 Pulse 完整能力 | 安全重试、延时、Cron/固定间隔、漏跑策略、计划版本、运行中取消、并发许可、配额/背压、可靠结果订阅、批量受理、独立任务核查/人工重试、查询筛选与事务Outbox接入 | 多实例领取/触发竞争、重试上限、取消竞争、队列隔离、积压恢复、事件重复交付 | 进行中:安全重试、计划调度、运行中取消、队列控制/限速/积压背压、跨命名空间应用配额、显式资源键许可及 SDK 场景已实现并通过全量回归;优先级及节点公平派发已实现并通过全量回归;可靠订阅核心、HTTP/WSS、管理 SDK 和管理示例已实现并回归;消费 SDK、协议示例及两项节点强杀回归已完成;业务 Inbox 场景、COMMIT响应丢失及消费者进程故障回归已完成;批量受理、SDK、接口与部分补交示例已完成全量回归;独立任务核查/人工重试、审计查询、两次真实HTTP回执丢失及完整示例已通过全量回归;业务键/创建时间筛选、SDK与示例已通过全量回归;任务直接来源(普通/人工重试/计划固定版本)及SDK示例已通过全量回归;事务Outbox接入待完成 |
| P4 Weave 主流程 | SDK 定义构建与发布校验、实例、顺序/分支/结构化并行汇合、信号/定时等待、版本绑定 | 重启接续、早到/重复信号、并行竞争、内部事件重放、发布版本兼容;端到端通用流程 | 待开发 |
| P5 Weave 恢复与查询 | 有界查询、暂停继续、取消、人工核查恢复、控制门控与审计 | 轮次与尝试独立预算;暂停/开始/回执/超时竞争;恢复保留预算;未知结果不盲目重复 | 待开发 |
| P6 生产验证与运维 | 完整监控、凭据轮换、备份恢复、滚动升级、运行手册、可复现负载和故障工具 | 对照生产验收清单执行,报告环境/指标/遗留项;容量、RPO/RTO 按真实拓扑验证 | 待开发 |
@@ -44,11 +44,23 @@ SDK、文档与示例随 P1–P5 同步开发,P7 是全量核对,不是最
| 批量任务受理 | 已实现[批量API](api/batch-tasks.md)、独立SDK及[补交示例](examples/batch.md);真实MySQL部分失败与HTTP响应丢失用例已通过,同键并发20轮及全量回归已通过,见[报告](reports/phase-3-batch-tasks.md) |
| 独立任务人工核查与重试 | 已实现[管理API及SDK](api/task-recovery.md)、专门权限、显式安全声明、证据/版本/审计和关联新任务;[完整场景](examples/recovery.md)及[回归报告](reports/phase-3-task-recovery.md)同步交付 |
| 任务查询筛选 | 已实现[业务键及创建时间查询](api/task-queries.md),v2游标绑定全部筛选、旧游标受限兼容、四种索引路径与[完整场景](examples/task-query.md);[回归报告](reports/phase-3-task-queries.md)同步记录 |
| 任务详情来源追踪 | 原功能要求能查看关联计划;当前TaskView未返回来源计划/触发记录。需补齐任务到计划及触发版本的查询,验证当前权限、同命名空间归属与来源缺失处理;流程来源随Weave接入 |
| 任务详情来源追踪 | 已实现[独立来源接口](api/task-source.md)、SDK和普通/计划/人工恢复场景,返回计划及触发固定版本;同命名空间归属、当前权限和来源缺失拒绝已通过[全量回归](reports/phase-3-task-source.md),流程来源随Weave接入 |
| 业务到平台的事务Outbox接入 | [事务Outbox设计](04-reliability-and-data.md#61-业务系统到平台) 尚缺完整接入示例;需业务变更与待发请求同事务、稳定提交身份、响应不明核对和发送恢复,保持核心SDK无ORM/数据库依赖 |
凭据安全重绑、历史清理、全量监控/容量与MySQL故障切换仍按P6执行;Weave的通用执行门控/内部事件接续随P4–P5落实,不将外部结果订阅当作内部流程引擎。
### P3 事务Outbox接入的剩余验收
以下为下一项实现与测试要求,目前尚未交付:
1. 独立业务示例module,以业务记录和待发请求同一个MySQL事务提交;核心SDK保持无ORM/数据库依赖,业务表示例也禁止外键,字段提供中文注释。
2. 同时冻结目标命名空间/队列、原幂等键、完整请求及内容摘要。相同业务操作重报不新建待发项,内容不同必须冲突;凭据原文不能进入Outbox或日志。
3. 提交、领取与确认分别使用短事务;HTTP在事务外执行。多发送进程通过数据库租约及递增代次协调,旧代次不能覆盖新结果;重启后继续读取持久化待发项。
4. 平台已受理但响应丢失、业务COMMIT回执未知、发送进程退出,都必须用原身份核对。只确认平台受理,不将受理标记当作业务执行成功。
5. 退避、发送次数及总发送期限均有上限,补发窗口不超过平台幂等保留期;权限、内容冲突、预算耗尽和不能可靠确认的响应需保留可核查记录,不生成新键绕过。
6. 真实数据库回归覆盖业务回滚、并发重复、发送竞争、过期租约、迟到确认和原始数字精度;真实HTTP丢响应、MySQL COMMIT响应丢失和发送进程SIGKILL后恢复一并验收。
7. 提供完整初始化、提交、运行/恢复、状态核对及失败处理命令;接入全量回归,记录实际测试证据后再完成P3范围核对。
## 4. SDK 与示例交付清单
@@ -101,6 +113,7 @@ SDK、文档与示例随 P1–P5 同步开发,P7 是全量核对,不是最
- [P3 批量任务受理回归](reports/phase-3-batch-tasks.md)
- [P3 人工核查与重试回归](reports/phase-3-task-recovery.md)
- [P3 业务键与时间查询回归](reports/phase-3-task-queries.md)
- [P3 任务直接来源回归](reports/phase-3-task-source.md)
- [接口手册](api/README.md)
- [SDK 接入](sdk/README.md)
- [通用场景示例](examples/README.md)

View File

@@ -9,6 +9,7 @@
| `GET /health/live` | 已实现 | [健康检查](health.md) |
| `GET /health/ready` | 已实现,验证数据库、迁移记录及零外键要求 | [健康检查](health.md) |
| `/v1/tasks` 提交、查询、分页与待执行取消 | 已实现,P3扩展业务键与创建时间筛选 | [任务接口](tasks.md) / [查询契约](task-queries.md) |
| `GET /v1/tasks/{task_id}/source` | P3已实现普通、人工重试与计划固定版本来源 | [来源查询](task-source.md) |
| `POST /v1/tasks:batch` | P3 已实现逐项受理、独立幂等、部分结果与补交 | [批量任务](batch-tasks.md) |
| `/v1/tasks/{task_id}:review` / `:retry` 与 `/operations` | P3 已实现带证据核查、关联新任务与操作审计 | [人工恢复](task-recovery.md) |
| `/v1/tasks/{task_id}/attempts` 与尝试详情 | P2 已实现 | [执行历史](execution-history.md) |

View File

@@ -165,6 +165,8 @@ ListSchedules 需要 queue_id;计划列表和 occurrences 均可用 limit(
FIRED 表示已创建单点任务;COALESCED 表示范围已合并到 task_id;SKIPPED 没有 task_id。它们都不是业务执行结果,继续 GetTask 查询,再通过 [尝试与证据接口](execution-history.md) 核对执行。
从任务反查计划使用[GetTaskSource](task-source.md),返回来源计划、触发记录、当时固定版本和合并边界。该只读引用需要tasks:read,完整计划/版本内容仍需schedules:read;发布新版本不改变老任务来源。
## 6. SDK 与完整示例
所有方法首参数为 context.Context,写操作需要稳定 key。ListSchedules 的参数为 `(ctx, queueID, SchedulePageRequest)`;ListScheduleOccurrences 为 `(ctx, scheduleID, SchedulePageRequest)`。
@@ -185,7 +187,9 @@ ORBIT_URL=http://127.0.0.1:8080 \
前置数据库与目录步骤见 [SDK 接入](../sdk/README.md)。源码:[完整调度示例](../../sdk/go/examples/schedules/main.go)。示例创建暂停的每秒计划,恢复后让自动 Worker 返回对象输入快照,查询两次完成,再暂停并排空。计划本身有十秒结束边界,任务与历史保留;重复运行生成独立身份,不调用外部业务系统。
```text
source_kind=SCHEDULE fixed_version=1
schedule=<计划ID> occurrence=<触发ID> task=<任务ID> version=1 state=SUCCEEDED
source_kind=SCHEDULE fixed_version=1
schedule=<计划ID> occurrence=<触发ID> task=<任务ID> version=1 state=SUCCEEDED
paused=true completed_tasks=2 current_version=1
worker_drained=true running=0

131
docs/api/task-source.md Normal file
View File

@@ -0,0 +1,131 @@
# 任务直接来源查询
状态:P3已实现服务端、独立SDK及普通任务、计划、人工恢复示例。接口只读,使用已有模型和索引,不增加数据库外键或迁移。验证证据见[回归报告](../reports/phase-3-task-source.md)。
## 1. 请求与权限
`GET /v1/tasks/{task_id}/source`
请求头:`Authorization: Bearer <token>`。不需要请求体、Content-Type或Idempotency-Key,不接受任何查询参数。task_id为32位小写十六进制ID;认证决定命名空间,URL不能覆盖它。
权限为`tasks:read`及任务所属队列范围。每次请求验证当前凭据;不存在、跨命名空间或不在队列范围的任务均返回404。只获得来源引用,不因此获得计划定义、模板、管理或执行权限;读取完整计划及固定版本仍需`schedules:read`,见[计划手册](schedules.md)。
```sh
curl "$ORBIT_URL/v1/tasks/$TASK_ID/source" \
-H "Authorization: Bearer $ORBIT_TOKEN"
```
## 2. 响应字段
HTTP 200,使用`request_id`和`data`信封;X-Request-ID与正文一致。下表字段均位于data。
| 字段 | 类型 / 必填 | 含义 |
| --- | --- | --- |
| task_id | string / 是 | 已授权查询的任务ID |
| kind | string / 是 | DIRECT、MANUAL_RETRY或SCHEDULE |
| retry_of | string / 仅MANUAL_RETRY | 同命名空间、同队列的直接原任务ID |
| schedule | object / 仅SCHEDULE | 触发该任务的固定关联,字段如下 |
| schedule.schedule_id | string / 是 | 来源计划ID |
| schedule.schedule_version | 十进制字符串 / 是 | 实际触发时的非零uint64版本,发布新版本不改写它 |
| schedule.occurrence_id | string / 是 | 唯一关联该任务的触发记录ID |
| schedule.scheduled_at | UTC RFC3339 / 是 | 原计划时间,最多微秒精度,与实际受理/执行时间分开 |
| schedule.decision | string / 是 | FIRED单点触发或COALESCED合并触发 |
| schedule.covered_until | UTC RFC3339 / 仅COALESCED | 合并范围的排除上界,严格晚于scheduled_at |
DIRECT表示普通任务受理,包括单项和批量受理;任务内部的自动安全重试仍属于同一个任务,不改变来源。MANUAL_RETRY表示[人工重试](task-recovery.md)创建的新任务,只返回直接父任务,不递归遍历整条重试链。父任务继续保留原历史。
SCHEDULE中的版本来自触发记录,不能用计划最新版本替换。COALESCED对应区间`[scheduled_at, covered_until)`;合并范围内由计划定义确定原始时间点,不承诺每个自然时间单位都有一次触发。SKIPPED未创建任务,因此不会成为任务来源。
普通受理的完整响应:
```json
{
"request_id":"44444444444444444444444444444444",
"data":{
"task_id":"11111111111111111111111111111111",
"kind":"DIRECT"
}
}
```
人工重试的完整响应:
```json
{
"request_id":"44444444444444444444444444444444",
"data":{
"task_id":"11111111111111111111111111111111",
"kind":"MANUAL_RETRY",
"retry_of":"22222222222222222222222222222222"
}
}
```
计划合并触发的完整响应:
```json
{
"request_id":"44444444444444444444444444444444",
"data":{
"task_id":"11111111111111111111111111111111",
"kind":"SCHEDULE",
"schedule":{
"schedule_id":"22222222222222222222222222222222",
"schedule_version":"1",
"occurrence_id":"33333333333333333333333333333333",
"scheduled_at":"2026-09-17T00:00:00Z",
"decision":"COALESCED",
"covered_until":"2026-09-17T00:03:00.000001Z"
}
}
}
```
单点触发返回decision=FIRED并省略covered_until。所有不适用的可选字段省略,不用null占位。来源不包含任务payload/result、计划模板、策略、凭据或执行租约秘密。任务当前状态另用GetTask读取。
## 3. 关联校验与错误
平台采用无外键设计,本接口在认证事务内显式核对命名空间、任务、队列、计划、不可变版本与触发记录。人工重试父任务须为同队列中已失败/取消的独立任务。无所有者但存在触发记录、悬空父任务、缺失版本、错误队列、未知所有者或当前未支持的门控均拒绝,不能把关联损坏降级成DIRECT。
| HTTP / code | 处理 |
| --- | --- |
| 400 INVALID_ARGUMENT | 检查task_id;删除不受支持、重复或格式错误的查询参数 |
| 401 UNAUTHENTICATED | 检查凭据、过期、撤销及应用/命名空间状态 |
| 403 PERMISSION_DENIED | 需要tasks:read动作权限 |
| 404 NOT_FOUND | 任务不存在或不在当前命名空间/队列范围;旧版本节点也可能没有本路由 |
| 503 UNAVAILABLE | 数据库或来源关联不能可靠确认;不返回部分来源,不推测DIRECT |
读取不改变任务状态、版本、额度、尝试或审计。网络错误可以在有限预算内重新读取;SDK不自动重试。持续503应排查数据关联和服务日志,不能通过删除来源字段“修复”,也不能根据来源查询失败重新提交任务。
## 4. SDK调用与场景
```go
func (c *Client) GetTaskSource(ctx context.Context, taskID string) (TaskSource, error)
```
下方为已有客户端与taskID的调用片段;完整初始化、错误处理和可运行程序见后面的示例。
```go
source, err := client.GetTaskSource(ctx, taskID)
if err != nil { return err }
switch source.Kind {
case "DIRECT":
fmt.Println("普通受理", source.TaskID)
case "MANUAL_RETRY":
fmt.Println("直接原任务", *source.RetryOf)
case "SCHEDULE":
fmt.Println("来源计划", source.Schedule.ScheduleID,
"固定版本", source.Schedule.ScheduleVersion,
"触发记录", source.Schedule.OccurrenceID)
}
```
SDK的ScheduleVersion为uint64,JSON仍为字符串;时间使用time.Time。SDK验证响应task_id一致性、来源种类与字段组合、ID、版本及时间范围;未知kind或矛盾数据返回错误,不返回可误用的部分来源。协议新增来源种类时,接入方需升级SDK再使用。
| 场景 | 完整源码 | 运行说明与新增输出 |
| --- | --- | --- |
| 单项受理、取消后读取来源 | [tasks](../../sdk/go/examples/tasks/main.go) | [SDK初始化](../sdk/README.md),source_kind=DIRECT |
| 按计划找到触发任务,再反查来源 | [schedules](../../sdk/go/examples/schedules/main.go) | [计划场景](schedules.md#6-sdk-与完整示例),source_kind=SCHEDULE、fixed_version=1 |
| 人工核查后创建关联新任务 | [recovery](../../sdk/go/examples/recovery/main.go) | [恢复场景](../examples/recovery.md),source_kind=MANUAL_RETRY、parent=原任务ID |
上述示例均运行在隔离回归中;新发布计划版本后老任务仍指向旧版本,由真实数据库与SDK集成测试验证。Weave流程来源随P4–P5实现,目前没有WORKFLOW响应。此接口为新增只读路由,不更改Task/TaskSummary或Worker消息结构,不增加权限配置;新客户端调用旧节点的404不能理解为DIRECT。

View File

@@ -116,6 +116,8 @@ curl "$ORBIT_URL/v1/tasks/$TASK_ID" -H "Authorization: Bearer $ORBIT_TOKEN"
SDK:`Client.GetTask(ctx, taskID)`。
任务直接来源独立通过`GET /v1/tasks/{task_id}/source`读取,SDK为`GetTaskSource(ctx, taskID)`;可定位普通受理、人工重试父任务、来源计划/触发记录/固定版本。使用相同的tasks:read和队列范围,详情见[来源查询](task-source.md)。来源未嵌入Task或列表摘要,读取完整计划仍需计划权限。
## GET /v1/tasks
权限:tasks:read。查询参数均只能出现一次:

View File

@@ -15,7 +15,7 @@
- 源码:[SDK 任务受理示例](../../sdk/go/examples/tasks/main.go)。
- 前置:完成迁移、初始化凭据、启动服务,在没有 Worker 消费的专用队列运行此受理/取消示例,详见 [SDK 接入](../sdk/README.md)。
- 输入:对象引用、格式与精确整数;提交两次同一身份,再查询、分页并带版本取消。
- 预期:重复请求返回同一任务,最终 CANCELLED/revision=2。当前不启动 Worker,不实际生成文件。
- 预期:重复请求返回同一任务,最终 CANCELLED/revision=2,source_kind=DIRECT。当前不启动 Worker,不实际生成文件。
- 异常:凭据失效、权限不足、内容冲突、版本竞争和未知网络结果,见 [任务接口](../api/tasks.md)。
- 清理:示例以取消结束;任务和审计历史保留。重复运行会生成独立示例任务。
@@ -153,3 +153,10 @@
- 步骤:提交三个模拟任务 → 精确业务键及时间范围过滤 → 每页一条遍历 → 验证上界排除 → 取消收尾。
- 预期:matched=2、pages=2、before_excluded=true、cancelled=3。
- 范围:普通提交/读取/取消权限;不调用外部系统、不启动Worker,所有历史保留,状态分页不是数据库快照。
## 已可运行:从任务定位来源
- [来源接口与SDK](../api/task-source.md)随现有tasks、schedules、recovery三个示例运行,无额外服务或数据库表。
- 步骤:取得任务ID → GetTaskSource → 区分普通提交/人工重试/计划触发 → 按权限读取父任务或固定计划版本。
- 预期:source_kind分别为DIRECT、MANUAL_RETRY、SCHEDULE;人工重试关联原任务,计划任务保留实际触发版本。
- 异常:来源缺失或归属不匹配返回503,不能降级为DIRECT;新计划版本不覆盖历史版本,引用查询不授予计划定义读取权限。

View File

@@ -35,16 +35,19 @@ ORBIT_URL=http://127.0.0.1:8080 \
3. 原键重报核查,确认同audit_id和deduplicated=true。
4. RetryTask声明可安全重新执行并指定新总预算60秒,取得retry_of指向原任务的新任务。
5. Worker开始新任务、报告SUCCEEDED;查询原任务仍FAILED、新任务SUCCEEDED。
6. 查询原任务操作列表及重试审计详情,排空并关闭Worker连接。
6. 查询原任务操作列表及重试审计详情,通过GetTaskSource核对新任务的直接原任务,排空并关闭Worker连接。
预期输出,标识由实际执行生成:
```text
source_kind=MANUAL_RETRY parent=<原任务ID>
source=<原任务ID> state=FAILED retry=<新任务ID> state=SUCCEEDED audit=<审计ID> operations=4
```
操作数包含本例受理、原结果、核查和人工重试;以本次实际查询为准。示例不删除任务、审计或尝试。重复运行创建独立演示任务,每次保留原历史。
[来源接口](../api/task-source.md)仅返回直接父任务,重复人工重试沿后继继续,不递归加载整条链;查询不产生新的审计或改写历史。
## 接入片段
下方在已有客户端和已核实的current任务上下文中调用;完整imports/main及错误处理见源码。

View File

@@ -0,0 +1,76 @@
# P3 任务直接来源回归
验证日期:2026-09-17。服务端、SDK和三类现有场景已接入直接来源查询;定向MySQL、基础检查及全量隔离回归均已通过,完整脚本正常退出,状态码0。业务事务Outbox仍是P3待交付项,Weave按P4–P5继续。
## 1. 实现范围
- [服务模型](../../pulse/service/source.go)与[存储查询](../../internal/storage/mysql/task_source.go):DIRECT、MANUAL_RETRY、SCHEDULE三类来源;计划ID、触发记录、冻结版本及合并范围;人工重试仅一跳父任务。
- [HTTP路由](../../internal/transport/httpserver/history.go)提供GET /v1/tasks/{task_id}/source,沿用tasks:read和队列范围,拒绝查询参数。
- [独立SDK](../../sdk/go/task_source.go)验证响应ID、类型组合、版本和时间,保留uint64精度;没有数据库依赖或自动重试。
- [接口手册](../api/task-source.md)、[普通提交](../../sdk/go/examples/tasks/main.go)、[计划](../../sdk/go/examples/schedules/main.go)及[人工恢复](../../sdk/go/examples/recovery/main.go)同步提供调用与输出。
来源独立读取,不改变Task/TaskSummary及Worker协议,不在派发路径增加关联查询。复用现有(namespace_id,task_id)触发唯一索引及计划版本键,不新增迁移、索引或持久化字段;平台仍为35个实体、289个中文注释字段。新只读结构的字段也均有中文说明。
## 2. 真实MySQL与HTTP
[TaskSource集成](../../internal/storage/mysql/task_source_integration_test.go)已验证:
1. 普通受理和人工派生返回正确类型及直接父任务,读取前后任务快照不变。
2. 跨命名空间、未授权队列返回NOT_FOUND,撤销凭据后拒绝继续查询;缺失或跨命名空间父任务返回UNAVAILABLE。
3. 计划发布v2后,已生成任务仍指向v1和原触发记录,任务内容不变。
4. 只有tasks:read的凭据能查询有限来源引用,但读取完整计划仍被PERMISSION_DENIED拒绝。
5. 实际HTTP拒绝非法ID、参数与编码,隐藏无权限任务;响应不包含模板、payload或租约秘密。
6. COALESCED来源保留原触发时间和排除上界。
7. 模拟无外键数据库中的悬空所有者、缺失版本、错误计划队列、反向关联残留、未知所有者及门控,均拒绝且返回零值而非部分来源;恢复正确关联后查询成功。
定向回归总计24.058秒(含包及升级开销),TaskSource四组9.46秒通过。v7旧库升级验证外键70→0、323个未替换索引组件保留、已有任务内容不变;应用资源升级夹具还原历史真实utf8mb4_0900_as_cs后重放后续迁移。该调整仅修正测试夹具,生产迁移000016的精确utf8mb4_0900_bin保持不变。
## 3. SDK与完整场景
[SDK单元](../../sdk/go/task_source_test.go)覆盖三类有效响应、FIRED/COALESCED、9007199254740993版本精度、错误task_id、未知种类、字段矛盾、非法版本/时间/ID以及本地拒绝不安全路径。
[计划真实HTTP集成](../../sdk/go/schedule_integration_test.go)在发布新版本后核对旧任务固定来源;[恢复真实HTTP集成](../../sdk/go/recovery_integration_test.go)在回执丢失后以原身份恢复,再查询直接来源与人工重试关联。
已有三个可运行程序新增输出,原输出继续保留:
```text
source_kind=DIRECT
source_kind=SCHEDULE fixed_version=1
source_kind=MANUAL_RETRY parent=<原任务ID>
```
这些行来自不同程序,不是同一条任务同时具有三种来源。完整启动命令分别见[SDK入门](../sdk/README.md)、[计划场景](../api/schedules.md#6-sdk-与完整示例)及[恢复场景](../examples/recovery.md)。
## 4. 复现与结果
macOS、Go1.27.1、Docker单实例MySQL8.4.10,随机测试凭据、回环端口和一次性数据库。脚本完成后清理隔离资源。
```sh
make fmt test vet build
make integration
```
普通未配置数据库的go test会跳过Integration,不能替代真实数据库回归。本轮全量脚本完成后的实际结果:
| 验证组 | 本轮结果 |
| --- | --- |
| fmt / race / vet / build | PASS |
| 全量MySQL / TaskSource四组 | PASS,108.438 / 9.98秒 |
| SDK Worker完整组 | PASS,87.120秒 |
| SDK计划 / 队列 / 批量 / 查询 | PASS,5.815 / 4.419 / 1.391 / 1.461秒 |
| SDK订阅管理 / 事件消费 | PASS,33.366 / 52.813秒 |
| SDK人工恢复与来源 | PASS,3.398秒 |
| Inbox数据库与消费者故障 | PASS,34.591秒 |
| SDK应用额度 | PASS,1.370秒 |
| 九项节点/Worker进程故障 | PASS,60.842秒;加上Inbox消费者,共十项进程故障 |
| 可运行程序 | 17个核心SDK示例 + 1个独立Inbox示例通过,三个新增来源输出符合预期 |
零外键和历史迁移校验继续通过;文档链接、JSON块及核心SDK无服务端/数据库依赖检查通过。上述耗时为这次正确性回归记录,不是吞吐或容量结论。没有使用中途PASS日志推断脚本完成。
## 5. 交付边界
- 此接口只读直接来源,没有链式递归、来源全文或逆向全量任务搜索;状态和执行历史使用对应查询接口。
- tasks:read只授予当前任务的有限来源引用,完整计划/版本仍独立鉴权。来源查询不产生执行权或恢复权限。
- 关联损坏返回503,需要排查;不自动猜测或修复归属。所有者与来源由写入事务固定,读取不依赖数据库外键。
- Weave流程来源随流程引擎实现,当前未知所有者明确拒绝;旧节点缺少新路由时404不能作为DIRECT使用。
- 本轮不新增执行/持久化协议,也不提供生产吞吐、数据清理或数据库故障切换保证;这些仍按P6验证。

View File

@@ -32,13 +32,14 @@ ORBIT_URL=http://127.0.0.1:8080 \
```text
liveness=alive readiness=ready scope=database_and_schema
source_kind=DIRECT
task=<32位任务ID> duplicate=true listed=1 final_state=CANCELLED revision=2
```
重复运行示例会新建一个独立任务并取消它,listed 数量可能增加,最多显示当前页 10 条。数据和审计保留,不执行硬删除。示例只演示受理闭环,尚不执行文件转换。
- [健康示例源码](../../sdk/go/examples/health/main.go):只读,无业务资源写入。
- [任务示例源码](../../sdk/go/examples/tasks/main.go):提交两次同一身份、获取当前状态、列表、带版本取消。
- [任务示例源码](../../sdk/go/examples/tasks/main.go):提交两次同一身份、获取当前状态、列表、带版本取消,再核对直接来源。
- 任务示例也接受 ORBIT_TOKEN 和 ORBIT_QUEUE_ID,环境值优先于凭据文件。
- 示例发生错误会打印错误并非零退出;打印内容不包含原始 token。
- 初始凭据 30 天有效。初始化行为和错误核对方式见 [凭据文档](../api/authentication.md)。
@@ -119,6 +120,7 @@ fmt.Println(cancelled.Task.State)
| Liveness / Readiness | Health | [健康](../api/health.md) |
| SubmitTask | SubmitTaskRequest / SubmitTaskResult | [任务](../api/tasks.md) |
| GetTask | taskID / Task | [任务](../api/tasks.md) |
| GetTaskSource | taskID / TaskSource,直接来源及计划固定版本 | [来源查询](../api/task-source.md) |
| ListTasks | ListTasksRequest / TaskPage,业务键及创建时间范围 | [查询](../api/task-queries.md) |
| CancelTask | taskID、key、CancelTaskRequest / CancelTaskResult | [任务](../api/tasks.md) |
| CreateQueue | key、CreateQueueRequest / CreateQueueResult | [队列](../api/queues.md) |