feat: expose workflow state events and persist signal transitions

This commit is contained in:
2026-09-18 09:27:45 +08:00
parent 082898e705
commit a4d9900e2c
34 changed files with 1499 additions and 27 deletions

View File

@@ -237,3 +237,11 @@ PollState新增FirstRound和FirstRoundAttemptsUsed,记录当前激活的首个
VersionScope新增6个中文注释字段:命名空间、定义版本、定义、原摘要、去重队列JSON、索引创建时间;当前36个实体、311个直接持久化字段声明,全部有中文注释。版本范围不可更新,发布与范围同事务,读取摘要还要核验原定义和关联,不以派生索引授予权限。回填仅遍历DSL步骤,忽略常量中相同字段;旧版本及实例原文不修改。
7个新实例复合索引加现有业务键索引覆盖定义/业务键/状态8种组合,按创建时间与ID分页;全部保留无外键和无级联。范围校验、迁移性能边界和接口见[查询手册](api/workflow-queries.md)。
## 流程事件派生索引(000025)
Event.WorkflowID为只读STORED生成列,从原不可变事件派生流程归属,非流程或非法标识为空;应用不得独立写入,也不能将它作为授权依据。索引为(namespace_id,workflow_id,occurred_at,id)。历史原文不变,不补造过去缺失的信号转换;当前36个模型、312个直接持久化字段均有中文注释,无外键及级联。
新运行器将PENDING信号的消费、拒绝或过期与原状态事件同事务保存,批量拒绝分32条追加但整笔事务原子提交。公开查询核对固定版本全部队列、步骤/信号归属及历史激活。原始事件按数据库记录时间分页,版本与时间均不构成可靠消费水位。详见[状态时间线接口](api/workflow-events.md)与[验证报告](reports/phase-5-events.md)。
升级先停止旧写入节点,应用000025再启新版本,防止混合节点继续遗漏信号转换;生成列和索引涉及历史行扫描与可能的表重建,需预演维护窗口、磁盘和锁等待。严格SQL模式下先校验十六进制字符再转换,异常历史范围保留NULL,不清理原记录。

View File

@@ -28,30 +28,30 @@
| P1 任务受理闭环 | 应用凭据与作用域权限、队列、幂等提交、查询、待执行取消、受理事件;SDK 客户端 | API/SDK 创建查询闭环;重复键与内容冲突、响应未确认重报、跨命名空间拒绝、参数边界 | 已完成并通过阶段回归(见 P1 报告;真实断路/提交 ACK 丢失注入留后续故障阶段) |
| P2 Worker 执行闭环 | WSS 接入、能力/容量、领取与开始、租约、续租、结果确认、排空与恢复;Worker SDK | 真 Worker 执行;失联/重连/重复确认/旧尝试拒绝;业务效果未知转核查;节点故障接管 | 已完成并通过阶段回归:服务端、自动 SDK、历史查询、完整 Schema 与真实进程强杀恢复;测试拓扑和剩余生产故障矩阵见 P2 验收报告 |
| P3 Pulse 完整能力 | 安全重试、延时、Cron/固定间隔、漏跑策略、计划版本、运行中取消、并发许可、配额/背压、可靠结果订阅、批量受理、独立任务核查/人工重试、查询筛选与事务Outbox接入 | 多实例领取/触发竞争、重试上限、取消竞争、队列隔离、积压恢复、事件重复交付 | 已完成平台功能阶段验收:[原范围逐项核对](reports/phase-3.md)、[本轮完整回归](reports/phase-3-delay-recovery.md)。补齐相对延迟、改参数关联示例和四种重试全停恢复场景;20个可运行示例全部通过。全平台生产门槛及SDK首版交付剩余项仍按P6–P7推进 |
| P4 Weave 主流程 | SDK 定义构建与发布校验、实例、顺序/分支/结构化并行汇合、信号/定时等待、版本绑定 | 重启接续、早到/重复信号、并行竞争、内部事件重放、发布版本兼容;端到端通用流程 | 定义格式/词法类型校验、不可变发布、独立SDK及六类节点定义例子已实现,已通过[子项验收](reports/phase-4-definitions.md);已补[有限决策器及内部结果交付](reports/phase-4-engine-core.md);[实例受理及首批事务](reports/phase-4-admission.md)已实现;[结果消费和根接续](reports/phase-4-runtime.md)已接入后台,顺序/分支/并行及真实进程恢复已验证;[TIMER与后续POLL轮次](13-workflow-clock.md)已接入;[信号消费和最终查询竞争](14-workflow-signals.md)已接入内部运行器;[内部控制与停止结清](15-workflow-controls.md)已接入;[内部核查与TASK新激活](16-workflow-recovery.md)已接入;等待恢复已接入内部服务;实例公共API/SDK与基础可运行场景已接入;流程任务来源已接入;历史激活/轮次/信号与信号审计已接入;实例筛选分页已接入;统一事件时间线范围核对与更多场景继续开发 |
| P5 Weave 恢复与查询 | 有界查询、暂停继续、取消、人工核查恢复、控制门控与审计 | 轮次与尝试独立预算;暂停/开始/回执/超时竞争;恢复保留预算;未知结果不盲目重复 | 有界查询轮次/尝试独立预算及原截止恢复已接入内部运行器;最终信号竞争及在途查询结清已接入;内部暂停/继续/取消与失败结清已接入;执行核查、步骤结论、解除核查及TASK新激活已接入;[POLL跨激活恢复](17-workflow-poll-recovery.md)已接入;等待恢复已接入内部服务;公共API/SDK已接入;流程任务来源已接入;历史激活/轮次/信号与信号审计已接入;实例筛选分页已接入;统一事件时间线范围核对与更多场景继续开发 |
| P4 Weave 主流程 | SDK 定义构建与发布校验、实例、顺序/分支/结构化并行汇合、信号/定时等待、版本绑定 | 重启接续、早到/重复信号、并行竞争、内部事件重放、发布版本兼容;端到端通用流程 | 定义格式/词法类型校验、不可变发布、独立SDK及六类节点定义例子已实现,已通过[子项验收](reports/phase-4-definitions.md);已补[有限决策器及内部结果交付](reports/phase-4-engine-core.md);[实例受理及首批事务](reports/phase-4-admission.md)已实现;[结果消费和根接续](reports/phase-4-runtime.md)已接入后台,顺序/分支/并行及真实进程恢复已验证;[TIMER与后续POLL轮次](13-workflow-clock.md)已接入;[信号消费和最终查询竞争](14-workflow-signals.md)已接入内部运行器;[内部控制与停止结清](15-workflow-controls.md)已接入;[内部核查与TASK新激活](16-workflow-recovery.md)已接入;等待恢复已接入内部服务;实例公共API/SDK与基础可运行场景已接入;流程任务来源已接入;历史激活/轮次/信号与信号审计已接入;实例筛选分页已接入;[状态事件时间线](api/workflow-events.md)已接入;独立轮询/恢复场景及全范围验收继续开发 |
| P5 Weave 恢复与查询 | 有界查询、暂停继续、取消、人工核查恢复、控制门控与审计 | 轮次与尝试独立预算;暂停/开始/回执/超时竞争;恢复保留预算;未知结果不盲目重复 | 有界查询轮次/尝试独立预算及原截止恢复已接入内部运行器;最终信号竞争及在途查询结清已接入;内部暂停/继续/取消与失败结清已接入;执行核查、步骤结论、解除核查及TASK新激活已接入;[POLL跨激活恢复](17-workflow-poll-recovery.md)已接入;等待恢复已接入内部服务;公共API/SDK已接入;流程任务来源已接入;历史激活/轮次/信号与信号审计已接入;实例筛选分页已接入;[状态事件时间线](api/workflow-events.md)已接入;独立轮询/恢复场景及全范围验收继续开发 |
| P6 生产验证与运维 | 完整监控、凭据轮换、备份恢复、滚动升级、运行手册、可复现负载和故障工具 | 对照生产验收清单执行,报告环境/指标/遗留项;容量、RPO/RTO 按真实拓扑验证 | 待开发 |
| P7 首版交付核对 | SDK 兼容与发布准备、完整 API 手册、场景示例、全量回归及交付清单 | 新接入者按文档跑通全部示例;所有首版能力可追溯到实现与测试;报告实际生产边界 | 待开发 |
SDK、文档与示例随 P1–P5 同步开发,P7 是全量核对,不是最后才开始补文档。
P4/P5定时等待与后续查询轮次的实现及回归记录见[时钟报告](reports/phase-4-clock.md)。外部信号与最终查询竞争见[信号报告](reports/phase-4-signals.md)。公共实例、控制、信号、六类恢复和操作审计已接入HTTP与独立SDK,见[公共接入报告](reports/phase-5-public-api.md)。流程任务来源及[历史查询](api/workflow-history.md)已接入,[实例筛选分页](api/workflow-queries.md)已接入,统一事件时间线及更多恢复示例仍须核对交付。
P4/P5定时等待与后续查询轮次的实现及回归记录见[时钟报告](reports/phase-4-clock.md)。外部信号与最终查询竞争见[信号报告](reports/phase-4-signals.md)。公共实例、控制、信号、六类恢复和操作审计已接入HTTP与独立SDK,见[公共接入报告](reports/phase-5-public-api.md)。流程任务来源及[历史查询](api/workflow-history.md)已接入,[实例筛选分页](api/workflow-queries.md)已接入,[状态事件时间线](api/workflow-events.md)已接入,更多恢复示例仍须交付。
### P4/P5 下一步实施顺序
1. 已实现FAIL_AFTER_SETTLED与显式取消的内部分支结清,见[控制报告](reports/phase-5-controls.md):持久取消意图、复用Pulse取消、收集已发出查询/任务结果、等待全部已激活工作结清后才进入失败或取消终态。效果未知仍保留核查。
2. 已实现实例暂停/继续/取消内部操作,以control_revision、操作幂等身份、明确原因及审计保护控制决定;暂停不延长原截止,继续不覆盖核查或取消状态。
3. 已实现内部执行核查、步骤结论、解除核查及TASK新激活和旧激活隔离,见[核查报告](reports/phase-5-recovery.md)。POLL跨激活恢复已实现(见[查询恢复](17-workflow-poll-recovery.md));[核查后PENDING接续和独立等待重建](18-workflow-wait-recovery.md)也已接入内部服务,保留原预算、轮次、结果和证据。
4. 实例/当前步骤/信号/控制/六类恢复及流程操作审计HTTP和独立SDK已接入,步骤查询返回实际激活代次;并行执行与信号回执场景已有可运行示例。激活/轮次/信号历史及信号资源审计已接入;实例筛选分页已接入;继续核对统一状态事件时间线,并提供独立轮询及恢复示例;[Pulse任务流程来源](api/task-source.md#5-流程固定来源)已交付。逐项验证原键恢复、权限、版本冲突、竞争与进程全停。
4. 实例/当前步骤/信号/控制/六类恢复及流程操作审计HTTP和独立SDK已接入,步骤查询返回实际激活代次;并行执行与信号回执场景已有可运行示例。激活/轮次/信号历史及信号资源审计已接入;实例筛选分页已接入;状态事件时间线已接入;继续提供独立轮询及恢复示例;[Pulse任务流程来源](api/task-source.md#5-流程固定来源)已交付。逐项验证原键恢复、权限、版本冲突、竞争与进程全停。
5. 转入P6/P7的生产故障、容量、运维、发布与全部文档核对。内部存储阶段通过不会提前勾选公共接口或生产验收。
公共接入按以下调用链推进;本批已接入启动/当前详情、控制、信号、六类恢复和流程操作审计,并提供独立SDK及基础示例。任务流程来源和有界历史查询也已接入。实例分页和独立查询示例已接入;以下统一事件时间线范围核对和更多独立场景继续交付:
公共接入按以下调用链推进;本批已接入启动/当前详情、控制、信号、六类恢复和流程操作审计,并提供独立SDK及基础示例。任务流程来源和有界历史查询也已接入。实例分页和独立查询示例已接入;状态事件时间线已接入;更多独立场景继续交付:
| 调用链 | 需要补齐的内容 | 验收重点 |
| --- | --- | --- |
| 启动与读取 | 显式固定版本启动、当前实例、步骤及当前激活代次;已补有界历史读取及实例筛选分页 | 原键丢回执恢复、当前权限、读取快照一致性、未激活步骤语义 |
| 控制与信号 | 暂停/继续/取消、固定步骤和代次的信号提交及原受理回执 | control_revision与通用revision区分、迟到/旧代次、暂停期间结果收集 |
| 核查与追踪 | 六类恢复、激活/轮次/等待/信号历史读取及信号管理审计已接入;统一状态事件时间线待核对;Pulse任务流程来源已交付 | 当前实例/步骤/任务版本、证据和显式声明、旧历史保留、有界响应和权限隔离 |
| 核查与追踪 | 六类恢复、激活/轮次/等待/信号历史读取及信号管理审计已接入;状态事件时间线已接入;Pulse任务流程来源已交付 | 当前实例/步骤/任务版本、证据和显式声明、旧历史保留、有界响应和权限隔离 |
| 通用接入场景 | 并行汇合、外部回执、有限轮询、暂停核查恢复的可运行SDK示例 | 真实Worker执行、完整进程退出后接续、未知效果保留、全链路回归 |
接口只使用已经落地的内部事务规则;SDK保持独立module,不能引用服务端模型或数据库实现。生产故障及容量结论仍由P6专门验收。
@@ -176,3 +176,7 @@ P4/P5定时等待与后续查询轮次的实现及回归记录见[时钟报告](
- [P2 SDK 协议阶段记录](reports/phase-2-sdk-protocol.md)
- [P2 自动 Worker 运行器记录](reports/phase-2-worker-runtime.md)
- [P2 执行历史与大载荷记录](reports/phase-2-execution-history.md)
### 状态事件时间线子项
已接入流程/步骤/信号状态事件的公共HTTP、独立SDK、原元数据详情与完整运行例子。000025仅派生索引,历史原字段保持;新增信号转换与状态同事务,批量失败整体回滚。当前阶段验证见[时间线报告](reports/phase-5-events.md),P4/P5全范围核对、独立POLL/人工恢复示例和P6/P7仍未完成。

View File

@@ -23,6 +23,7 @@
| [12 Weave结果消费与推进](12-workflow-runtime.md) | 后台消费、根接续、事务与进程恢复,及尚未完成的等待/控制边界 |
| [13 Weave定时等待与查询轮次](13-workflow-clock.md) | 原截止、轮次/尝试预算、时钟检查点、升级与全停恢复 |
| [流程历史查询](api/workflow-history.md) | 指定历史激活、查询轮次、信号摘要与信号资源审计 |
| [流程状态时间线](api/workflow-events.md) | 原始流程/步骤/信号状态事件、分页和历史详情 |
| [接口手册](api/README.md) | 实际接口状态、调用说明与后续接口规划 |
| [SDK 与场景](sdk/README.md) | 可运行示例、接入方法及分阶段 SDK 交付 |

View File

@@ -29,6 +29,7 @@
| `/v1/workflow-definitions` 创建、发布与固定版本读取 | P4定义子项已实现,实例另用启动接口 | [定义接口](workflow-definitions.md)、[格式规范](workflow-definition-format.md) |
| `/v1/workflows`、步骤详情、控制、信号及操作审计 | 已接入HTTP与独立SDK | [实例接口](workflows.md) |
| 历史激活/轮次/信号列表、历史激活详情及信号资源审计 | 已接入有界分页HTTP与独立SDK | [历史查询](workflow-history.md) |
| `/v1/workflows/{id}/events` 及单条事件详情 | 已接入不可变状态事件、审计权限及独立SDK | [状态时间线](workflow-events.md) |
| `/v1/workflows/{id}/recovery/*` 六类人工恢复 | 已接入有证据恢复及独立SDK | [恢复接口](workflow-recovery.md) |
未实现路由返回 404。健康检查就绪不表示任务执行、定时调度或流程引擎已经可用。

158
docs/api/workflow-events.md Normal file
View File

@@ -0,0 +1,158 @@
# 流程状态事件时间线
HTTP 与独立 Go SDK 已接入。用于查看流程、用户定义步骤与信号已经保存的状态变化;原事件不会被后续恢复覆盖。运行方法见[并行作业与回执示例](../examples/workflow.md),验证记录见[时间线报告](../reports/phase-5-events.md)。
## 1. 路由、权限与范围
| 方法与路径 | 权限 | Go SDK |
| --- | --- | --- |
| `GET /v1/workflows/{id}/events` | workflows:audit:read | ListWorkflowEvents(ctx, id, page) |
| `GET /v1/workflows/{id}/events/{event}` | workflows:audit:read | GetWorkflowEvent(ctx, id, event) |
成功为200,使用 `Authorization: Bearer <token>`,无需请求体或幂等键。id和event均为32位小写十六进制。两条路由都要求显式审计权限,普通workflows:read不包含此权限;开发初始化用 `--workflow-audit-access`。每次读取都核验当前命名空间及实例固定版本引用的全部队列,包括尚未执行的分支。
数据库派生的workflow_id只用于缩小查询范围,不能授予权限。服务端继续核对真实实例、步骤、信号及事件引用的历史激活归属;内部`$root`步骤不出现在公开时间线。详情必须同时指定父实例和事件ID,不能用全局事件ID越权。
本接口提供逻辑状态事件。任务执行次数、原输入结果、POLL业务轮次、等待预算和人工决定通过下列接口关联查看:
| 要查看的内容 | 接口 |
| --- | --- |
| 当前步骤、任务引用、等待原因和剩余预算 | [实例与步骤详情](workflows.md) |
| 指定历史激活的输入输出、等待、POLL轮次 | [流程历史](workflow-history.md) |
| Pulse尝试与迟到/矛盾证据 | [执行历史](execution-history.md) |
| 管理操作人、原因、证据及前后摘要 | [流程操作审计](workflows.md#6-操作审计与错误处理)、[信号审计](workflow-history.md) |
| 任务的固定版本、步骤和历史激活来源 | [任务来源](task-source.md#5-流程固定来源) |
事件元数据只保留当时实际写入的引用,例如activation_id或audit_id;旧事件没有的字段不会用当前资源补造。操作审计与Pulse尝试不复制进本接口,避免将不同记录误认为同一种状态转换。
## 2. 摘要分页
只接受可选limit和cursor。limit为1–100,省略默认20;SDK的0表示省略。cursor最多1024字节,需进行URL编码。未知、重复、非法参数返回400;详情不接受查询参数。
```sh
curl --get "$ORBIT_URL/v1/workflows/$WORKFLOW_ID/events" \
--header "Authorization: Bearer $ORBIT_TOKEN" \
--data-urlencode 'limit=20'
```
响应示例:
```json
{
"request_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"data": {
"workflow_id": "11111111111111111111111111111111",
"revision": "12",
"items": [{
"id": "22222222222222222222222222222222",
"workflow_id": "11111111111111111111111111111111",
"aggregate_kind": "workflow_signal",
"aggregate_id": "33333333333333333333333333333333",
"aggregate_revision": "2",
"type": "workflow.signal.changed",
"state_scope": "SIGNAL",
"state": "CONSUMED",
"occurred_at": "2026-09-18T08:00:00.123456Z"
}]
}
}
```
| 字段 | 含义 |
| --- | --- |
| workflow_id | 本页授权的实例 |
| revision | 读取本页时的实例版本,uint64字符串;不是事件消费水位 |
| items | 有界摘要;空列表为[],不带payload或业务输入结果 |
| next_cursor | 还有更旧记录时返回;没有下一页则省略 |
| items[].id | 原不可变事件ID |
| aggregate_kind / aggregate_id | 来源类型及身份:workflow、workflow_step、workflow_signal |
| aggregate_revision | 来源资源当时的版本,uint64字符串,各资源独立计数 |
| type | 当时保存的事件类型 |
| state_scope / state | WORKFLOW、STEP或SIGNAL,以及该对象当时保存的状态 |
| step_key | 仅步骤事件返回,取自固定定义,不返回内部根步骤 |
| occurred_at | 数据库记录事件的UTC微秒时间,RFC3339;不是外部业务发生时间 |
按occurred_at、id双键倒序,相同微秒由ID稳定定位。游标绑定命名空间、实例和事件查询种类,不能用于其他实例、操作审计或激活列表。跨页不承诺固定快照,新提交或迟到提交的事件可能落在已经翻过的位置;重新从第一页读取可查看更新。
时间戳及ID均不能表达严格因果或提交顺序。例如同一个启动事务中,首步状态可能先于workflow.started写入;跨资源aggregate_revision不能比较大小。定时退避可能改变资源版本而不改变状态,因此状态事件的版本也可能不连续。需要可靠处理Pulse结果时使用[持久订阅](subscriptions.md),不要将此审计分页当作消息消费协议。
## 3. 类型与原事件详情
| type | aggregate_kind | state_scope | 记录内容 |
| --- | --- | --- | --- |
| workflow.started | workflow | WORKFLOW | 首次启动、固定定义及版本 |
| workflow.advanced | workflow | WORKFLOW | 持久推进时保存的实例状态 |
| workflow.controlled | workflow | WORKFLOW | 暂停、继续、取消的控制结果 |
| workflow.recovered | workflow | WORKFLOW | 人工恢复决定及当时关联 |
| workflow.blocked | workflow | WORKFLOW | 进入核查等阻塞状态 |
| workflow.stopped | workflow | WORKFLOW | 停止意图结清后的终态 |
| workflow.step.changed | workflow_step | STEP | 步骤当时状态和已记录的激活/原因 |
| workflow.signal.accepted | workflow | SIGNAL | 保存信号受理记录,state可为PENDING、REJECTED或EXPIRED |
| workflow.signal.changed | workflow_signal | SIGNAL | 已有PENDING信号被消费、拒绝或过期 |
`workflow.signal.accepted`沿用历史格式,aggregate_id和aggregate_revision属于实例;state_scope为SIGNAL,信号ID在payload.signal_id中。受理成功不等于信号被消费,受理时就被拒绝的记录不会再制造一个虚假的PENDING转换。
详情data在摘要字段外增加payload,为原事件元数据对象,最大64KiB。例如上述信号消费事件的payload:
```json
{
"workflow_id": "11111111111111111111111111111111",
"signal_id": "33333333333333333333333333333333",
"from": "PENDING",
"state": "CONSUMED",
"disposition": "WAIT_MATCHED",
"consumed_wait_id": "44444444444444444444444444444444"
}
```
```sh
curl "$ORBIT_URL/v1/workflows/$WORKFLOW_ID/events/$EVENT_ID" \
--header "Authorization: Bearer $ORBIT_TOKEN"
```
信号消费、过期和拒绝,与对应事件在同一数据库事务提交。批量拒绝最多处理单实例既有上限1024条,每32条批量追加事件;任一批失败会回滚整笔转换,重复处理不重复制造事件。该原子性覆盖平台记录,不保证外部系统业务副作用只发生一次。
## 4. SDK调用
类型见[workflow_events.go](../../sdk/go/workflow_events.go)。返回revision和aggregate_revision自动解析为uint64;Payload为json.RawMessage,保留精确数字,进一步解析未知元数据时用json.Decoder.UseNumber或明确整数类型。
```go
cursor := ""
for {
page, err := client.ListWorkflowEvents(ctx, workflowID,
orbit.HistoryPageRequest{Limit: 20, Cursor: cursor})
if err != nil { return err }
for _, event := range page.Items {
fmt.Printf("%s %s %s %s\n", event.OccurredAt, event.Type,
event.StateScope, event.State)
// 仅在需要展开某条事件时读取原元数据。
if event.Type == "workflow.signal.changed" {
detail, err := client.GetWorkflowEvent(ctx, workflowID, event.ID)
if err != nil { return err }
fmt.Printf("%s\n", detail.Payload)
}
}
if page.NextCursor == "" { break }
cursor = page.NextCursor
}
```
完整[workflow示例](../examples/workflow.md)运行真实Worker,保存外部回执后按每页5条读取时间线,核对CONSUMED事件的原PENDING状态及赢家等待ID。
## 5. 错误、升级与验证边界
| HTTP / code | 处理 |
| --- | --- |
| 400 / INVALID_ARGUMENT | 修正非法ID、limit、cursor或参数;不要删除父资源或切换查询种类重试 |
| 401 / UNAUTHENTICATED | 检查有效凭据 |
| 403 / PERMISSION_DENIED | 显式授权workflows:audit:read |
| 404 / NOT_FOUND | 实例/事件不存在、父子错配、范围不可访问;不按全局ID降级查找 |
| 503 / UNAVAILABLE | 数据库故障、已选事件归属损坏、未知历史类型或超大元数据;保留现场核查,不能把空页当作成功 |
只读请求可在原实例与游标下有限重试;数据改变后结果可能不同。取消HTTP只取消本次读取,不控制流程。SDK拒绝父资源不一致、无效摘要、排序不符和超限详情,不自动补造历史。
迁移000025新增只读派生列及`(namespace_id,workflow_id,occurred_at,id)`索引,无外键和级联。已有事件原字段不变;无合法流程范围的历史行派生为NULL,不进入流程时间线。新读取仍核验实际归属,但本接口不是全库损坏扫描,无法自动找出被错误范围隐藏的历史行。
旧版本没有保存的信号转换不会回填。部署时先停止旧写入节点,完成迁移再启动新节点,否则混合写入期间可能继续缺少转换事件。STORED生成列和索引需要读取历史数据并可能重建表,生产升级须预演锁等待、时长及磁盘空间;不承诺无停机DDL。旧不可变迁移保持原校验和。
真实MySQL验证包括升级原文保留、零外键、相同时间分页、授权、跨父资源、消费/拒绝/过期、分批写入失败回滚、重复处理和历史激活恢复;HTTP/SDK及完整例子已接入标准回归。大库索引开销、生产故障域、主从切换与全量运维仍属于P6/P7验收。

View File

@@ -1,6 +1,6 @@
# 流程激活、查询轮次、信号与信号审计
状态:HTTP与独立Go SDK已接入;本页查询明确指定的历史激活,不跟随逻辑步骤的当前激活。实例筛选分页、统一状态事件时间线及更多独立恢复场景仍按[开发计划](../08-development-plan.md)核对与交付。测试与范围见[本批报告](../reports/phase-5-history.md)。
状态:HTTP与独立Go SDK已接入;本页查询明确指定的历史激活,不跟随逻辑步骤的当前激活。[实例筛选分页](workflow-queries.md)和[状态事件时间线](workflow-events.md)已接入,更多独立恢复场景仍按[开发计划](../08-development-plan.md)交付。测试与范围见[本批报告](../reports/phase-5-history.md)。
## 1. 路由与调用规则

View File

@@ -153,6 +153,8 @@ name/payload_version/target_step_key必填,分别最多128/32/64个ASCII名称
## 6. 操作审计与错误处理
[状态事件时间线](workflow-events.md)另提供流程、步骤和信号的不可变状态变化,以及原事件元数据;同样要求显式审计权限。此处操作审计保留管理决定的操作人、原因、证据及前后摘要,两类记录通过已保存的身份关联,不将当前资源状态反填为历史。
ListWorkflowOperations接受HistoryPageRequest:limit默认20、范围1–100;cursor最大1024字节,绑定命名空间、流程ID和查询种类,不可跨资源复用。data为 `{items, next_cursor?}`;每项含 id、workflow_id、operation_id、actor_id、action、created_at,按时间及ID倒序。GetWorkflowOperation除这些字段外还返回reason、evidence_ref(可空省略)、before、after JSON摘要。单独读取正文,避免列表聚合大结果。
该接口当前查询resource_kind=workflow的启动、推进、控制和恢复审计;独立任务核查审计通过恢复回执的task_audit_id关联。信号自身的受理状态通过GetWorkflowSignal读取;[信号资源审计及历史激活查询](workflow-history.md)使用独立路由,统一状态事件时间线仍待核对交付。

View File

@@ -12,7 +12,7 @@
- [完整命令、输入输出与失败处理](workflow.md)、[独立SDK源码](../../sdk/go/examples/workflow/main.go)。
- 两个任务并行处理并汇合,计时等待后接收显式目标代次的信号,再执行后续任务;最终三个任务完成并有界排空。
- 启动及信号原键重复不会建立新的实例或信号。
- 启动及信号原键重复不会建立新的实例或信号;分页查看原状态事件,核对信号消费及赢家等待。
## 已可运行:业务事务与任务提交Outbox

View File

@@ -13,7 +13,7 @@ chmod 700 .local
go run ./cmd/orbit-admin bootstrap \
--application workflow-example --namespace default --environment development \
--queue workflows --workflow-access --workflow-run-access \
--workflow-signal-access --worker-access \
--workflow-signal-access --workflow-audit-access --worker-access \
--output .local/workflow.credentials.json
go run ./cmd/orbit
```
@@ -31,7 +31,7 @@ go run ./examples/workflow
## 2. 调用链与输出
CreateWorkflowDefinition → PublishWorkflowVersion(v1) → StartWorkflow → 原键再次StartWorkflow → 自动Worker并行执行 → GetWorkflowStep读取当前信号契约与代次 → SendWorkflowSignal → 原键再次发送 → 后继任务完成 → GetWorkflow → GetWorkflowSteps和GetTaskSource核对三个任务的固定来源 → Worker有界排空。
CreateWorkflowDefinition → PublishWorkflowVersion(v1) → StartWorkflow → 原键再次StartWorkflow → 自动Worker并行执行 → GetWorkflowStep读取当前信号契约与代次 → SendWorkflowSignal → 原键再次发送 → 后继任务完成 → GetWorkflow → GetWorkflowSteps和GetTaskSource核对三个任务的固定来源 → 读取历史激活与信号 → 分页读取状态事件并核对消费记录 → Worker有界排空。
预期输出中的ID每次运行不同:
@@ -39,6 +39,7 @@ CreateWorkflowDefinition → PublishWorkflowVersion(v1) → StartWorkflow →
workflow=<32位实例ID> state=SUCCEEDED result={"text":"HELLO ORBIT"} start_deduplicated=true signal_deduplicated=true
workflow_sources_verified=3 fixed_version=v1
workflow_history_verified=true signal_state=CONSUMED
workflow_timeline_verified=true events=<事件数> signal_transition=PENDING->CONSUMED
worker_drained=true started=3 confirmed=3
```
@@ -56,4 +57,8 @@ worker_drained=true started=3 confirmed=3
[公共SDK集成测试](../../sdk/go/workflow_instances_integration_test.go)还实际运行:启动响应丢失的原键恢复;暂停/继续、定时等待、信号消费和取消;UNKNOWN执行核查、步骤结论及解除核查;剩余尝试内TASK重试与SIGNAL换代;确认PENDING后沿原查询预算继续。使用`make integration`在一次性环境复现。
历史激活和信号列表已接入,示例核对指定历史等待的winner与信号CONSUMED状态。实例筛选分页、更多独立业务示例及生产验收仍按[计划](../08-development-plan.md)推进。
历史激活和信号列表已接入,示例核对指定历史等待的winner与信号CONSUMED状态。[实例筛选分页](workflow-query.md)已接入;更多独立轮询/恢复示例及生产验收仍按[计划](../08-development-plan.md)推进。
## 5. 状态事件审计
例子使用显式审计权限,按每页5条调用ListWorkflowEvents,再用GetWorkflowEvent展开已消费信号,核对原状态PENDING和历史等待ID。当前成功流程的事件仍保留早先WAITING等状态。事件数量可能随实际推进次数变化,不将数量写死为业务契约;示例会确认必要消费事件存在。字段、分页限制和旧版本历史缺口见[时间线手册](../api/workflow-events.md)。

View File

@@ -0,0 +1,58 @@
# P4/P5 流程状态事件时间线验证记录
日期:2026-09-18。本批范围是流程状态事件的分页、详情、HTTP、独立SDK,以及信号消费/拒绝/过期的事务事件。P4/P5全范围核对、独立POLL/人工恢复场景和P6/P7仍未完成。
## 实现与接口
- `GET /v1/workflows/{id}/events`及`/{event}`,对应ListWorkflowEvents和GetWorkflowEvent。两条路由都要求显式workflows:audit:read,并核对固定版本全部队列。
- 原始workflow、workflow_step、workflow_signal事件按数据库记录时间与ID倒序,不展现内部根步骤。摘要默认20、最多100条,原元数据详情不超过64KiB。
- 实例、步骤和信号是独立聚合,revision不能跨资源比较;时间/ID不能推断提交水位或可靠消费进度。旧事件只展示当时保存的字段,不用当前激活改写历史。
- PENDING信号的新转换与原状态事件同事务提交。批量拒绝每32条插入事件,任一批失败时全部回滚;保留单实例1024条历史信号上限。
- 000025增加只读派生列和分页索引,不添加外键或级联,不补造历史缺失的信号转换。索引只用于查找,实际资源归属仍由服务端核验。
- 36个持久化模型、312个直接字段均有中文注释;新增列同步中文COMMENT。
接口、字段及SDK片段见[时间线手册](../api/workflow-events.md)。[workflow完整例子](../examples/workflow.md)在真实Worker任务完成后,按每页5条核对信号原状态与赢家等待ID。原激活/轮次、Pulse尝试及操作审计仍通过各自接口关联,不能把逻辑时间线误称为所有底层记录的单一事件流。
## 环境与命令
macOS arm64、Go 1.27.1、Docker MySQL 8.4.10,一次性隔离数据库;真实Orbit进程、HTTP及WSS Worker。未访问生产数据库。
```sh
make fmt test vet build
DOCKER=/usr/local/bin/docker make integration
```
本地通过GO参数指定工具链。标准集成入口增加WorkflowEventsSDK,沿用21个SDK例子和2个独立业务模块,原有流程/Worker/订阅进程故障用例继续执行。
## 验证记录
| 检查 | 结果 |
| --- | --- |
| fmt、race单元回归、vet与构建 | 通过 |
| 流程及步骤真实推进、列表无payload、详情与摘要一致 | 定向MySQL通过 |
| 权限、队列限制、跨实例事件与跨种类游标 | 定向MySQL通过 |
| 消费赢家、竞争者拒绝、重复处理 | 定向MySQL通过,状态与事件不重复 |
| 单条事件写入失败 | 定向MySQL通过,赢家等待/信号/后继全部回滚 |
| 70条待处理信号停止结清,第二批事件写入失败 | 定向MySQL通过,70条信号仍PENDING、已插入批次全部回滚;恢复后70条REJECTED各有事件 |
| 同一SQL批次相同微秒时间的分页 | 定向MySQL通过,每页7条覆盖相同时间组,无漏无重 |
| 过期、错误派生范围及超大元数据 | 定向MySQL通过;不返回损坏候选的部分页 |
| v24→v25升级与重跑 | 通过,旧8个原字段全部相同、精确JSON保留、非法范围NULL、只读生成列不可覆盖、索引列序正确、外键0 |
| 真实HTTP独立SDK | 通过,11个原事件分6页,信号CONSUMED与流程CANCELLED保留 |
| 完整workflow示例 | 通过,3个Worker任务成功并排空,20条事件包含PENDING→CONSUMED和赢家等待 |
| 定义与原五组公共实例SDK回归 | 定向链路通过 |
| 新增旧激活恢复后事件读取与损坏归属拒绝 | 全量存储回归通过,恢复后原事件保持,错误历史归属返回UNAVAILABLE |
| 完整标准集成脚本 | 通过,退出码0;21个SDK例子、2个独立业务模块、流程/Worker/订阅进程故障全部完成 |
定向存储12.734秒,SDK组26.530秒,其中时间线SDK2.26秒。这些是测试执行耗时,不是吞吐或延迟指标。当前312个模型字段中文注释检查缺失0;Markdown检查1096个本地链接、68个JSON块,错误0。
回归修正了两处测试准备错误:尚在等待的错误关联信号会在受理时直接REJECTED,不能作为PENDING批量转换夹具,因此改为前置TIMER尚未结束时收到的早到信号;SDK模拟响应必须提供合法32位request_id。严格SQL模式还揭示UNHEX非法值在生成列DDL中会报错,因此转换前先核验全部字符,真实v24旧库重跑升级通过。修复没有放宽权限或移除归属检查。
## 生产边界和剩余工作
- 索引只是查询范围,不是授权真相;被非法范围隐藏的历史行不会由单实例分页自动检出,需要数据库写权限保护与专项核查。
- 旧节点未保存的信号转换不会自动出现。先停止旧写入节点、应用迁移,再由新版接管;未实现无协调混合写节点升级。
- STORED生成列和索引涉及旧行扫描及可能的表重建。大库DDL时长、空间、锁等待、查询稀疏性及信号批量事务开销仍需P6真实容量验证。
- 本地进程故障回归不等于跨故障域高可用、MySQL主从切换或生产备份恢复验收。平台事务原子性也不等于外部业务副作用只执行一次。
- 继续独立轮询/人工恢复示例、P4/P5原范围核对和P6/P7;当前持续目标保持进行中。
完整标准集成脚本退出码0:存储组237.549秒,流程进程恢复48.726秒,最后Worker/订阅进程故障组97.407秒。新时间线6组存储场景与v24升级通过;历史v7→当前迁移再次确认70个外键全部移除、323个原索引组成部分和原任务保留。生产容量与高可用边界仍按上述未验证项处理。

View File

@@ -208,3 +208,5 @@ P2 已提供底层协议、[自动 Worker 运行器及示例](worker-runtime.md)
流程任务同样调用`GetTaskSource`,kind为WORKFLOW时读取workflow中的固定版本、步骤、历史激活代次、查询轮次和直接恢复父任务。该代次不表示当前等待目标;发送信号须另读GetWorkflowStep。完整字段及兼容边界见[来源接口](../api/task-source.md#5-流程固定来源),[workflow示例](../examples/workflow.md)实际核对三个任务来源。
[ListWorkflows及完整查询示例](../api/workflow-queries.md)已接入,固定筛选沿游标分页,覆盖未执行分支的全部队列权限。
[ListWorkflowEvents / GetWorkflowEvent](../api/workflow-events.md)按实例读取不可变状态事件,要求显式workflows:audit:read;[完整workflow示例](../examples/workflow.md)核对信号从PENDING到CONSUMED的原事件与赢家等待。游标用于审计翻页,不是可靠订阅水位。