Files
orbit/docs/examples/workflow-poll.md

5.4 KiB
Raw Permalink Blame History

有界轮询:请求重试与业务轮次分别计数

完整源码通过公共SDK发布POLL定义,启动真实Worker,并请求一个本机HTTP渠道夹具。流程先由TASK向本机渠道提交一次作业,受理回执提供固定operation_id,随后POLL只查询这个作业;平台没有集成任何具体业务渠道。

同一命令依次运行两个流程:

场景 渠道响应 平台结果
success 提交一次;首次查询503,重试PENDING,下一轮DONE 2个业务轮、3次查询尝试,SUCCEEDED
exhausted 提交一次;两次查询都成功返回PENDING 2个业务轮、2次查询尝试,NEEDS_REVIEW

1. 环境与启动

需要Go 1.27.1、MySQL 8.4+,设置专用ORBIT_MYSQL_DSN。从仓库根目录初始化:

go run ./cmd/orbit-migrate up
mkdir -p .local
chmod 700 .local
go run ./cmd/orbit-admin bootstrap \
  --application poll-example --namespace default --environment development \
  --queue workflows --workflow-access --workflow-run-access --worker-access \
  --output .local/poll.credentials.json
go run ./cmd/orbit

bootstrap只执行一次,凭据文件存在时不会覆盖。另开终端,从仓库根目录运行:

cd examples
ORBIT_URL=http://127.0.0.1:8080 \
ORBIT_CREDENTIALS_FILE=../.local/poll.credentials.json \
go run ./workflow-poll

程序自行创建并关闭本机HTTP夹具,不需要启动第三方系统,不向公网提交操作。正式接入使用HTTPS/WSS和分角色凭据,将只读查询处理器替换为自己的渠道调用。

2. 定义与调用链

CreateWorkflowDefinition → PublishWorkflowVersion(v1) → StartWorkflow → 自动Worker提交一次 → 按受理回执中的身份查询 → GetWorkflow/GetWorkflowStep → ListWorkflowPollRounds → GetTaskSource/ListTaskAttempts → Worker排空。

输入为{"operation_id":"本次示例的固定操作身份"}。submit任务只允许一次尝试并使用RECONCILE_ONLY,提交结果未知时必须核查;query通过WorkflowRef("submit")引用已保存受理回执,每轮及同轮重试保持这个身份。结果契约是STRING枚举PENDING/DONE。定义中设置:

poll := orbit.WorkflowPoll{
    Task: orbit.WorkflowTask{
        // 处理器、输入/输出契约和队列等完整字段见可运行源码。
        Retry: orbit.RetryPolicy{
            MaxAttempts: 2, InitialDelayMS: 1000,
            MaxDelayMS: 1000, AttemptTimeoutMS: 5000,
        },
        TimeoutMS: 20000,
        RecoverySafety: orbit.RecoveryIdempotent,
    },
    MaxRounds: 2, TimeoutMS: 30000, IntervalMS: 1000,
    Pending: []string{"PENDING"}, Succeeded: []string{"DONE"},
}

本片段说明预算配置,不是可单独发布的完整定义;源码包含所有必填字段。流程总时限45秒,查询总时限30秒,轮次包含首次;实际任务还受流程及节点原截止限制。

受控渠道的503表示明确拒绝只读查询,因此返回WorkerFailure{Code:"QUERY_TEMPORARY", Retryable:true}。传输错误仍返回普通error,保留未知结果,由冻结的安全策略决定后续。只有明确知道请求失败才可声明WorkerFailure,不能把任意网络超时归类为明确失败。

HTTP 200的PENDING直接作为成功结果返回给Orbit,不由Worker自己循环或sleep。Weave保存轮间等待、释放Worker槽位,并在原间隔后创建下一轮任务。轮次耗尽不假定外部作业失败,也不重置预算或再次提交外部作业。

3. 预期输出及验证

前面的scenario、operation、workflow字段每次不同。两个最终结果为:

poll_scenario=success state=SUCCEEDED submissions=1 rounds=2 attempts=3 requests=3 deadline_preserved=true worker_drained=true
poll_scenario=exhausted state=NEEDS_REVIEW submissions=1 rounds=2 attempts=2 requests=2 deadline_preserved=true worker_drained=true

程序从实际历史读取两轮,每页1条;成功场景第一轮包含FAILED和SUCCEEDED两次尝试,第二轮只有一次SUCCEEDED。耗尽场景两轮请求都成功,逻辑步骤仍进入核查,没有current_task_id或next_poll_at继续运行。每轮任务来源必须指向原实例与轮次,原查询/实例截止保持不变,每个流程只有一次POST提交;Worker实际执行与确认总数包含该提交,所以成功场景共4次、耗尽场景共3次,其中查询请求分别为3次和2次。

4. 失败、重跑与清理

程序总运行期限60秒,每个Worker排空期限5秒。发生意外状态、权限错误、响应损坏或预算不符会非零退出,不自动换版本、续期或解除核查。

每次重新运行会创建新的独立示例身份,不代表对上一次未知响应的恢复。生产调用方应持久保存幂等键及完整命令;响应不明时原命令原键核对,不能重新执行此示例来替代恢复。

正常结束关闭本机渠道与Worker,保留两个流程和所有历史,其中exhausted流程有意保留NEEDS_REVIEW供查看。不要将该示例放进生产定时任务无限创建待核查记录。真实渠道状态和证据需由接入方核实,再通过人工恢复API决定后续;示例不会伪造最终成功。

回归入口是make integration。SDK预算与字段见定义格式,原截止与查询语义见时钟约定,阶段证据见P4/P5核对。