Files
orbit/docs/examples/delayed-task.md

3.8 KiB
Raw Permalink Blame History

相对延迟与原请求恢复

源码:delayed-task/main.go。示例提交等待1500毫秒的对象任务,启动自动Worker,核对实际执行历史,再在任务完成后重报原请求。处理器原样返回示例JSON,无外部副作用。

准备与运行

先完成迁移和Worker凭据初始化,启动当前Orbit。凭据需要任务提交、读取及Worker连接/消费权限,队列须有可用额度。仓库根目录执行:

cd examples
ORBIT_URL=http://127.0.0.1:8080 \
  ORBIT_CREDENTIALS_FILE=../.local/worker.credentials.json \
  go run ./delayed-task

也可用ORBIT_TOKEN和ORBIT_QUEUE_ID覆盖凭据文件中的对应值。示例总上下文20秒、任务总时限15秒、单次执行5秒、最多1次尝试;每次运行使用独立操作及处理器身份,不会消费其他处理器的任务。

预期输出:

task=<任务ID> delay_ms=1500
state=SUCCEEDED attempts=1 no_early_start=true original_receipt=true worker_drained=true

检查依据是同一个数据库的CreatedAt、AvailableAt及尝试创建/开始时间,不把客户端墙钟或sleep结束当作执行授权。Worker正常排空后退出;任务、结果和审计保留。

SDK调用

以下为函数中的调用片段,完整imports及错误处理见源码:

request := orbit.SubmitTaskRequest{
    QueueID: queueID,
    Handler: "object.prepare", HandlerVersion: "v1", PayloadVersion: "v1",
    Payload: json.RawMessage(`{"object_ref":"objects/input"}`),
    DelayMS: 5000,
    TaskTimeoutMS: 60000,
    Retry: orbit.RetryPolicy{MaxAttempts: 1, AttemptTimeoutMS: 10000},
}
accepted, err := client.SubmitTask(ctx, operationKey, request)
if err != nil { return err }
fmt.Println(accepted.Task.ID, accepted.Task.AvailableAt)

delay_ms相对首次成功受理事务中的数据库时间计算,保存为available_at。同一幂等键重报仍提交原等待时长;不按当前时间重算available_at,不生成新键。响应是原受理回执,即使任务后来已经成功,回执中仍可能是WAITING;当前状态通过GetTask查询。

指定绝对时刻时使用AvailableAt并令DelayMS为0。非零delay_ms和available_at不能同时提供。等待时长必须小于task_timeout_ms;总时限包含等待时间。start_deadline_at不能早于计算后的available_at。所有时间规则及400/409错误见任务接口。

服务端停机、队列暂停、没有兼容Worker或额度不足都可能让开始时间晚于available_at;到期后才可领取,不承诺准点执行。自动失败重试使用retry中的退避策略,不再次应用初始delay_ms。

失败与持久化边界

示例网络错误时非零退出,已打印任务ID可用于核对;不在同一次运行中换键重提。真实接入须在第一次请求前保存操作身份和请求,可使用业务事务Outbox。本例生成的新身份仅用于独立演示,重新运行不是上一次进程的恢复。

Outbox若使用delay_ms,等待从Orbit受理开始计算,不从本地业务事务或Outbox创建时间计算。需要固定业务时刻时冻结available_at;若发送时该时刻已超出接口容差,按拒绝结果核查,不静默改成“从现在起再等”。

旧服务不识别delay_ms。先更新服务端,再让调用方启用该字段;省略/零值保持旧请求摘要。计划模板拒绝非零delay_ms,时间由计划规则定义。人工重试的新开始时间使用其专门接口参数,不继承原任务的初始延迟。

make integration执行此例、真实HTTP/Worker延迟用例,以及重试退避期间全节点退出后的恢复测试;结果见本轮报告。