Files
orbit/docs/api/worker.md

152 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Worker 通信与执行契约 v1
已实现服务端执行事务、WebSocket 接入、[独立 Go 底层协议 SDK](../sdk/worker.md)、[自动 Worker 运行器](../sdk/worker-runtime.md) 与 [尝试/证据查询](execution-history.md),通过 [P2 阶段验收](../reports/phase-2.md),包含真实 WSS、协议 Schema、自动续租、ACK 丢失/断网恢复及进程强杀后的节点接管。底层 WorkerConnection 不自动管理处理器;NewWorker / Run 提供自动管理。
## 1. 接入与身份
入口 `GET /v1/worker/connect`,子协议必须为 `pulse.worker.v1`。Authorization 使用 Bearer 凭据;禁止 URL 查询参数。握手先校验 workers:connect,消费控制操作再次校验 workers:consume、队列范围和凭据有效性。
初始化开发凭据可显式增加 Worker 权限:
```sh
go run ./cmd/orbit-admin bootstrap \
--application worker-demo --namespace default --environment development \
--queue objects --worker-access --output .local/worker.credentials.json
```
默认 bootstrap 仍只有 P1 的五项权限,现有凭据不会自动扩权。生产细粒度凭据管理在 P6 完成。
当前 orbit 命令监听 HTTP,开发可使用 ws;生产需要受控的 TLS 终止。WSS 回归使用真实 TLS 测试服务器及受信任测试证书,没有跳过证书校验。传输库锁定 github.com/coder/websocket v1.8.15,使用上下文、读写期限、子协议和默认 Origin 校验,关闭压缩。[上游版本记录](https://github.com/coder/websocket/releases/tag/v1.8.15)、[上游接口文档](https://pkg.go.dev/github.com/coder/websocket@v1.8.15)。
## 2. 帧格式
只接受 JSON 文本帧;单帧最多 512 KiB,业务结果最多 256 KiB。重复键、未知字段、无效 Unicode 和非法数值按 HTTP 相同规则拒绝。
机器可读契约及各方向定义见 [JSON Schema 说明](worker-schema.md)。控制字段必须显式提供;epoch/sequence 等计数使用无前导零的规范十进制字符串。请求禁止响应字段,空字符串/null 也不例外。
```json
{
"protocol_version":"1",
"type":"task.start",
"message_id":"44444444444444444444444444444444",
"session_id":"33333333333333333333333333333333",
"body":{
"task_id":"11111111111111111111111111111111",
"attempt_id":"22222222222222222222222222222222",
"epoch":"1",
"lease_secret":"<执行秘密,仅通过受控连接传输>"
}
}
```
所有 ID 为 32 位小写十六进制;epoch、sequence、revision 用十进制字符串。message_id 标识一次操作,重连重报保持不变;session_id 必须换为当前连接身份。服务端响应以 reply_to 关联请求:
```json
{
"protocol_version":"1",
"type":"error",
"message_id":"55555555555555555555555555555555",
"reply_to":"44444444444444444444444444444444",
"session_id":"33333333333333333333333333333333",
"error":{"code":"LEASE_LOST","message":"attempt no longer grants execution authority"}
}
```
普通成功响应 type=ack,body 为下表对应结果。服务端主动派发 type=task.assign,无 reply_to。错误仅包含稳定分类和公开消息,不包含 SQL、业务参数或秘密。
## 3. 注册、恢复与容量
连接后 5 秒内必须发送 worker.hello,hello 不携带 session_id。
| hello 字段 | 含义 |
| --- | --- |
| instance_id | Worker 进程实例 ID;进程重启必须换新值 |
| instance_secret | 32 字节随机秘密的无填充 base64url 编码,共 43 字符;同进程重连保留 |
| queue_id | 当前进程绑定队列 |
| capabilities | 1–32 个 handler / handler_version / payload_version 精确版本组合,不可重复 |
| capacity | 总执行槽数量,1–256,不是可用槽的累加值 |
| cancellation_notifications | 可选 bool,默认 false;true 接收 task.cancel 通知,自动 Worker 默认开启 |
重连必须保持凭据、队列、处理器集合和进程秘密,处理器集合的排列顺序不影响身份。新连接递增会话代次并使旧会话失效。知道 instance_id 或 task_id 不能接管执行。
worker.welcome 返回 session_id、epoch、server_time、expires_at、lease_duration_ms、draining。当前窗口为会话 45 秒、执行租约最多 30 秒;注册及能力声明不等于开始授权。
**派发在收到第一次 worker.capacity 确认后才启用**,便于客户端先恢复旧尝试。
| 类型 | body | 返回 |
| --- | --- | --- |
| worker.resume | AttemptRef,字段见上方 task.start 示例 | 当前 LeaseStatus;成功迁移有效尝试到新会话,不创建尝试或延长期限 |
| worker.capacity | sequence 字符串、capacity 0–256、drain bool | 更新后的 welcome 字段 |
| task.assign | 服务端主动发送 | task 完整任务、attempt_id、epoch、lease_secret、lease_until、server_time |
capacity 使用单调递增序号和覆盖值。同序号同内容可重复,同序号不同内容或旧序号冲突;capacity=0 不释放已有任务的并发许可。drain=true 是进程级持久化排空,重连保留;后续必须保持 drain=true,尝试清除返回 STATE_CONFLICT。新进程使用新实例身份。
一个 Worker 进程当前绑定一个队列。可以运行多个 Worker 进程或后续 SDK 实例消费不同队列;不能通过重连静默切换队列。
## 4. 开始、续租与结果
| 类型 | body | 语义 |
| --- | --- | --- |
| task.start | AttemptRef | 领取后再次检查当前会话、尝试、租约、队列暂停及流程门控,保存 RUNNING 后确认 |
| task.renew | AttemptRef | 只续期当前 RUNNING;新消息可续租,重复原消息只取回原回执 |
| task.finish | ref: AttemptRef、outcome、result、error_code、可选 retryable | 保存明确结果或未知效果;返回操作回执和当前授权 |
outcome 为 SUCCEEDED / FAILED / UNKNOWN / CANCELLED。result 为非 null JSON 或证据引用。非成功结果必须带 1–64 字符的稳定 error_code;SUCCEEDED 不带错误分类。retryable 省略为 false,只有 FAILED 可设 true。CANCELLED 要求已保存取消意图且确认本次停止,不能用普通 context 错误推断;协议与升级顺序见 [取消契约](cancellation.md)。FAILED/true 受次数与时限限制进入退避;UNKNOWN 仅在冻结策略为 IDEMPOTENT、未取消且预算允许时自动恢复,其他情况转 NEEDS_REVIEW。历史不确定效果不会被后续失败或取消覆盖;完整规则见 [安全重试](retries.md)。
开始、续租和结束返回 CommandResult:
```json
{
"receipt":{
"operation":"start",
"task_state":"RUNNING",
"attempt_state":"RUNNING",
"task_revision":"3",
"lease_until":"2026-09-17T08:00:30Z",
"disposition":"APPLIED"
},
"lease":{
"active":true,
"state":"RUNNING",
"lease_until":"2026-09-17T08:00:30Z",
"server_time":"2026-09-17T08:00:00Z"
},
"deduplicated":false
}
```
receipt 是原操作的不可变确认;lease 是本次重新核验的执行权,两者不能混用:
- 只有 lease.active=true、lease.state=RUNNING、没有 cancel_requested_at,且仍在保守的本地有效期内,才允许处理器推进。LEASED 的 active 只表示预占有效。取消后的 active 可为 true,用于确认当前结果;不允许继续业务执行或延长期限。
- 原 start 回执可能仍表示 RUNNING,但当前 lease.active=false;旧 ACK 不能让已过期、已结束或已被替换的尝试复活。
- 有效期不超过租约窗口、会话期限、任务总截止和从 authorized_at 起计算的单次尝试时限。
- 客户端需要扣除请求总耗时及安全余量,用本地单调时钟停止执行,不能假定本地墙上时钟与数据库一致。
- 同结果重报不重复释放许可或产生成功事件;即使换 message_id,也返回该结果第一次已应用的回执,不借用后续尝试的状态。同消息改变内容或 retryable 返回 IDEMPOTENCY_CONFLICT。
- 迟到、未开始或与已保存结果冲突的内容,经过身份和秘密验证后保存为 EVIDENCE_ONLY;不改变任务权威结果,不当作新的执行授权。
- 断线后原结果仍保留稳定消息 ID,可在新会话恢复/核对后重报。不会因重连创建第二次业务执行。
## 5. 领取、并发与回收
平台在同一事务中分配队列并发许可、创建尝试、递增任务执行代次和次数、保存 LEASED 与派发事件。领取本身消耗一次 max_attempts 预算,包括最终未获开始授权的尝试,预算不会因重连或过期恢复重置。
运行中的进程总容量跨其所有旧/新会话统计。声明容量减少、断开连接或重复结果,都不能重复释放额度。已实施队列 max_concurrency、rate_per_second 及未终结任务上限;参数含义、窗口突发、暂停及降额语义见 [队列资源控制](queues.md)。应用级配额、业务键许可与公平性仍在 P3 推进。
领取前核对速率窗口及已有 LEASED 预留,满额时不新建尝试。Start 在同一队列事务内消费开始预算,原 ACK 重报不重复计数。领取后若配置降额,Start 可能返回 RATE_LIMITED;保持原消息身份在剩余租约内退避核对。续租、结果确认、取消及恢复不消费新开始额度。
每个节点每 2 秒发起一批恢复扫描,每批最多 100 项:
- 未批准开始即到期:有剩余次数和截止时间时按冻结策略退避;否则无历史不确定效果为 FAILED,有未核实效果为 NEEDS_REVIEW。
- 已批准开始后失联:尝试 UNKNOWN;RECONCILE_ONLY 转 NEEDS_REVIEW,IDEMPOTENT 仅在次数及时限允许时退避重试,并保留 effect_uncertain。
- WAITING 超过总截止或最晚开始时间:无历史不确定效果为 FAILED,否则 NEEDS_REVIEW。
- 回收再次锁定队列、任务、尝试并读取数据库时间,与续租/完成串行化;多个节点不能重复释放许可或重复终结事件。
安全重试已使用同一决策逻辑处理有效结果与租约回收;下一执行时间持久化在任务中,重启不丢失等待。当前不提供人工重试或核查解除接口。
## 6. 连接保护与当前边界
当前节点上限 128 条 Worker 连接;每连接入站队列 4 帧、出站队列 8 帧,派发保留 ACK 缓冲空间,每秒最多发起 4 次新派发尝试。读空闲期限 60 秒、写期限 5 秒、单个数据库控制操作期限 8 秒。慢消费者导致连接关闭时,已提交状态仍由稳定身份恢复。
这些是有界的开发基线,不代表经过容量压测的生产参数。当前同队列操作使用较粗的行锁协调,吞吐与公平性需要 P6 按负载验证。服务退出会显式关闭被 HTTP Upgrade 接管的连接;断开不会直接撤销外部已发出的请求。
协议 Schema 和真实进程强杀恢复已通过回归,见 [P2 阶段验收](../reports/phase-2.md)。[运行中取消](cancellation.md) 已实现并通过回归;凭据轮换、数据库故障切换、跨主机演练与容量验收属于后续生产验证。自动运行器对非协作处理器提供有界退出与状态报告,不能强制停止其外部副作用。