12 KiB
流程激活、查询轮次、信号与信号审计
状态:HTTP与独立Go SDK已接入;本页查询明确指定的历史激活,不跟随逻辑步骤的当前激活。实例筛选分页和状态事件时间线已接入,更多独立恢复场景仍按开发计划交付。测试与范围见本批报告。
1. 路由与调用规则
所有接口为GET,成功200,使用Authorization: Bearer <token>,不需要请求体或幂等键。{id}是流程实例ID,{activation}是激活ID,{signal}是信号ID,{operation}是审计记录ID;均为32位小写十六进制。{key}是固定定义中的步骤键,1–64个ASCII字符,首位字母或数字,之后允许字母、数字、_ . -,禁止内部$root。操作审计的operation_id不是查询路径中的审计ID。
| 路径 | 权限 | SDK方法 |
|---|---|---|
/v1/workflows/{id}/steps/{key}/activations |
workflows:read | ListWorkflowActivations(ctx, id, key, page) |
/v1/workflows/{id}/steps/{key}/activations/{activation} |
workflows:read | GetWorkflowActivation(ctx, id, key, activation) |
/v1/workflows/{id}/steps/{key}/activations/{activation}/rounds |
workflows:read | ListWorkflowPollRounds(ctx, id, key, activation, page) |
/v1/workflows/{id}/signals |
workflows:read | ListWorkflowSignals(ctx, id, page) |
/v1/workflows/{id}/signals/{signal}/operations |
workflows:audit:read | ListWorkflowSignalOperations(ctx, id, signal, page) |
/v1/workflows/{id}/signals/{signal}/operations/{operation} |
workflows:audit:read | GetWorkflowSignalOperation(ctx, id, signal, operation) |
服务端先校验命名空间和固定流程引用的全部队列,再读取子资源。普通流程读取权限不包含审计权限;bootstrap用--workflow-audit-access显式签发审计权限。知道激活、任务、信号或审计ID不能绕过父资源权限。
四个列表只接受可选limit、cursor。limit为十进制整数1–100,省略默认20;SDK的HistoryPageRequest.Limit=0表示省略。cursor最多1024字节,按URL查询参数编码,必须来自相同查询种类、实例以及对应步骤/激活/信号。未知、重复或非法参数返回400;详情不接受查询参数。
每页最多读取limit+1条判断后续,空列表返回items: [],没有下一页时省略next_cursor。游标不是授权凭据;改权限后继续分页仍重新授权。翻页之间不是固定数据库快照,状态可能变化、新记录可能产生;要看最新记录需重新从第一页开始,不能把游标用于执行或确认操作。
2. 激活列表和单次详情
列表按sequence倒序,不聚合input、output、查询预算或等待正文。返回类型是WorkflowActivationPage:
| 字段 | 类型与含义 |
|---|---|
| instance_id、step_id | 字符串,已验证父实例与逻辑步骤 |
| revision | 十进制字符串,本页读取时的实例版本;SDK为uint64 |
| current_activation_id | 可选字符串,本页读取时的当前激活;尚未激活时省略 |
| items | 激活摘要数组,未激活步骤为[] |
| next_cursor | 可选字符串,后续位置 |
每项含id、step_id、sequence(正uint32)、state、revision(uint64字符串)、created_at、updated_at;task_id仅用于TASK直接任务,completed_at仅已保存结束时间时返回。时间均为UTC RFC3339。state反映这条激活当前保存的状态,不代表整个实例状态;核查可能改变记录状态,列表不是每次状态变化的事件流水。
下面是恢复后的第二页,当前激活已经是第2代,本页仍读取第1代:
{
"request_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"data": {
"instance_id": "11111111111111111111111111111111",
"revision": "12",
"step_id": "22222222222222222222222222222222",
"current_activation_id": "44444444444444444444444444444444",
"items": [{
"id": "33333333333333333333333333333333",
"step_id": "22222222222222222222222222222222",
"sequence": 1,
"state": "FAILED",
"revision": "3",
"task_id": "55555555555555555555555555555555",
"created_at": "2026-09-18T08:00:00Z",
"updated_at": "2026-09-18T08:00:01Z",
"completed_at": "2026-09-18T08:00:01Z"
}]
}
}
详情的data为{instance_id, revision, step, activation, input, output?, poll?, wait?}:
step是逻辑步骤当前视图,activation是明确请求的历史激活摘要,两者的激活ID和代次允许不同。input/output只属于指定激活。缺失output与显式null不同,精确JSON数字由SDK的json.RawMessage保留;不会展开其他激活大正文。- POLL的
poll返回这一激活的first_round、first_round_attempts_used、used_rounds、冻结上限、原截止和最后任务。字段与当前查询详情一致,范围改为指定激活。 - SIGNAL、TIMER和有最终信号的POLL返回该激活的wait,包含原等待ID、原截止、状态和已有赢家。恢复后旧等待仍可读,新激活不能延长原截止或替换旧winner。
- TASK尝试、未知结果和迟到证据通过task_id继续查询执行历史。人工决定的前后摘要通过流程操作审计读取。
3. POLL轮次列表
data为{instance_id, revision, activation_id, items, next_cursor?},items按业务轮round倒序。每项为{id, activation_id, round, task_id, created_at};round是正uint32,其他身份为字符串。
必须明确指定一个POLL激活;TASK或其他节点调用返回400。人工恢复同一业务轮会新建激活和任务,因此“第1代的业务第1轮”和“第2代的业务第1轮”可以同时存在。先遍历激活,再遍历每个激活的轮次,不能把激活序号、业务轮次和Pulse尝试epoch混为一谈。
{
"request_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"data": {
"instance_id": "11111111111111111111111111111111",
"revision": "20",
"activation_id": "44444444444444444444444444444444",
"items": [{
"id": "66666666666666666666666666666666",
"activation_id": "44444444444444444444444444444444",
"round": 1,
"task_id": "77777777777777777777777777777777",
"created_at": "2026-09-18T08:00:02Z"
}]
}
}
列表显式验证每轮任务属于该命名空间、激活、固定队列和门控。关联损坏不返回部分成功,也不利用外键推断归属。GetTaskSource可以反向核对固定来源。
4. 信号与信号资源审计
信号列表data为{workflow_id, revision, items, next_cursor?},按accepted_at和id倒序。每项含id、workflow_id、revision、name、payload_version、target_step_key、target_activation_sequence、state、accepted_at、expires_at,有处置原因时增加disposition。列表不携带payload、correlation_key、actor_id或evidence_ref;完整原信号使用GetWorkflowSignal读取。
早期未核验历史可能payload_version为空、target_activation_sequence为0,列表保留这些事实,不补造可执行身份。CONSUMED表示该信号已消费,单条详情的consumed_wait_id与指定历史激活的wait.winner_signal_id可以交叉核对。
信号操作列表data为{items, next_cursor?},按created_at和id倒序,每项含id、workflow_id、signal_id、operation_id、actor_id、action、created_at。当前受理动作action为workflow.signal。操作详情的data直接是该摘要,再增加reason、可选evidence_ref、before和after:
{
"request_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"data": {
"id": "88888888888888888888888888888888",
"workflow_id": "11111111111111111111111111111111",
"signal_id": "99999999999999999999999999999999",
"operation_id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"actor_id": "cccccccccccccccccccccccccccccccc",
"action": "workflow.signal",
"created_at": "2026-09-18T08:00:02Z",
"reason": "verified external completion",
"evidence_ref": "proof:event-1",
"before": null,
"after": {"signal_id": "99999999999999999999999999999999", "state": "PENDING"}
}
}
上例after省略其他受理身份字段,完整内容以原操作保存的JSON为准。after是原受理审计,之后信号已消费也不能把其中PENDING改成CONSUMED。此接口只查workflow_signal资源,流程推进/控制/恢复操作在流程审计中。普通信号消费状态通过Get/List查看,不能将本接口解释成所有内部状态事件的统一时间线。
5. SDK调用场景
以下代码接在已配置client与ctx、已知workflowID及stepKey的调用方中;page使用SDK类型,与服务端模型无依赖:
cursor := ""
for {
page, err := client.ListWorkflowActivations(ctx, workflowID, stepKey,
orbit.HistoryPageRequest{Limit: 20, Cursor: cursor})
if err != nil { return err }
for _, activation := range page.Items {
detail, err := client.GetWorkflowActivation(ctx, workflowID, stepKey, activation.ID)
if err != nil { return err }
fmt.Printf("activation=%s sequence=%d state=%s\n",
detail.Activation.ID, detail.Activation.Sequence, detail.Activation.State)
// 按需读取单次结果;禁止拿当前step的代次冒充历史激活代次。
}
if page.NextCursor == "" { break }
cursor = page.NextCursor
}
POLL继续用ListWorkflowPollRounds(ctx, workflowID, stepKey, activation.ID, page)分页获取该次激活的任务,再按任务查询尝试和证据。信号场景用ListWorkflowSignals定位旧代次和当前代次的信号;具备审计权限后用ListWorkflowSignalOperations和GetWorkflowSignalOperation读取原因与原受理证据。
可运行并行作业示例会核对已完成等待的历史赢家与CONSUMED信号。SDK真实链路测试另外覆盖TASK恢复、SIGNAL换代、POLL同轮恢复及下一业务轮分页;入口为make integration。调用方法见SDK源码,各字段中文注释见独立类型。
6. 错误、部署与兼容
| HTTP / 错误码 | 含义与处理 |
|---|---|
| 400 INVALID_ARGUMENT | 身份、步骤键、分页参数或游标范围错误;或非POLL读取轮次。修正查询,不能丢掉筛选继续 |
| 401 UNAUTHENTICATED | 凭据无效或过期,按认证协议处理 |
| 403 PERMISSION_DENIED | 缺少读取或显式审计权限 |
| 404 NOT_FOUND | 父/子资源不属于该作用域、不存在或队列不可访问;不跨资源查找 |
| 503 UNAVAILABLE | 关联损坏或数据库暂不可用;保留资源身份并检查服务记录,不能将空列表当作成功 |
所有查询只读,不重算截止、重置预算、消耗轮次或触发恢复。SDK拒绝非法路径/分页及响应父资源不匹配;不自动创建新身份。读操作网络失败可以按原资源重读,状态可能已经前进。
服务端需先应用000023_workflow_signal_history,只增加(namespace_id,workflow_id,accepted_at,id)索引;原数据、迁移历史、模型字段和零外键要求保持。维护窗口和DDL锁需按目标数据库演练。当前SDK仍为开发版,使用与服务端匹配的开发提交;历史/事件功能已进入P4/P5阶段验收,生产容量、跨版本和高可用验收仍未完成。