feat: add durable Worker execution and WSS server
This commit is contained in:
146
docs/api/worker.md
Normal file
146
docs/api/worker.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Worker 通信与执行契约 v1(开发中)
|
||||
|
||||
已实现服务端执行事务、WebSocket 接入和真实 WSS 回归。**P2 尚未完成**:独立 Go SDK 的 Worker 运行器、自动重连/续租、处理器生命周期与优雅退出还在开发。本页记录当前可验证的服务端契约,不把测试客户端当作可交付 Worker SDK。
|
||||
|
||||
## 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
|
||||
{
|
||||
"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,不是可用槽的累加值 |
|
||||
|
||||
重连必须保持凭据、队列、处理器集合和进程秘密,处理器集合的排列顺序不影响身份。新连接递增会话代次并使旧会话失效。知道 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 是进程级持久化排空,重连保留,不能通过后续消息清除;新进程使用新实例身份。
|
||||
|
||||
一个 Worker 进程当前绑定一个队列。可以运行多个 Worker 进程或后续 SDK 实例消费不同队列;不能通过重连静默切换队列。
|
||||
|
||||
## 4. 开始、续租与结果
|
||||
|
||||
| 类型 | body | 语义 |
|
||||
| --- | --- | --- |
|
||||
| task.start | AttemptRef | 领取后再次检查当前会话、尝试、租约、队列暂停及流程门控,保存 RUNNING 后确认 |
|
||||
| task.renew | AttemptRef | 只续期当前 RUNNING;新消息可续租,重复原消息只取回原回执 |
|
||||
| task.finish | ref: AttemptRef、outcome、result、error_code | 保存明确结果或未知效果;返回操作回执和当前授权 |
|
||||
|
||||
outcome 为 SUCCEEDED / FAILED / UNKNOWN。result 为非 null JSON 或证据引用。FAILED/UNKNOWN 必须带 1–64 字符的稳定 error_code;SUCCEEDED 不带错误分类。当前 FAILED 成为任务失败终态,UNKNOWN 转 NEEDS_REVIEW;策略化自动重试在 P3 实现。
|
||||
|
||||
开始、续租和结束返回 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,且仍在保守的本地有效期内,才允许处理器推进。LEASED 的 active 只表示预占有效。
|
||||
- 原 start 回执可能仍表示 RUNNING,但当前 lease.active=false;旧 ACK 不能让已过期、已结束或已被替换的尝试复活。
|
||||
- 有效期不超过租约窗口、会话期限、任务总截止和从 authorized_at 起计算的单次尝试时限。
|
||||
- 客户端需要扣除请求总耗时及安全余量,用本地单调时钟停止执行,不能假定本地墙上时钟与数据库一致。
|
||||
- 同结果重报不重复释放许可或产生成功事件。同消息不同内容返回 IDEMPOTENCY_CONFLICT。
|
||||
- 迟到、未开始或与已保存结果冲突的内容,经过身份和秘密验证后保存为 EVIDENCE_ONLY;不改变任务权威结果,不当作新的执行授权。
|
||||
- 断线后原结果仍保留稳定消息 ID,可在新会话恢复/核对后重报。不会因重连创建第二次业务执行。
|
||||
|
||||
## 5. 领取、并发与回收
|
||||
|
||||
平台在同一事务中分配队列并发许可、创建尝试、递增任务执行代次和次数、保存 LEASED 与派发事件。领取本身消耗一次 max_attempts 预算,包括最终未获开始授权的尝试,预算不会因重连或过期恢复重置。
|
||||
|
||||
运行中的进程总容量跨其所有旧/新会话统计。声明容量减少、断开连接或重复结果,都不能重复释放额度。当前已实施队列 max_concurrency;rate_per_second、其他配额和调度策略在 P3 完成。
|
||||
|
||||
每个节点每 2 秒发起一批恢复扫描,每批最多 100 项:
|
||||
|
||||
- 未批准开始即到期:有剩余次数和截止时间时,延后 1 秒重派;否则 FAILED。
|
||||
- 已批准开始后失联:NEEDS_REVIEW,尝试 UNKNOWN,不能因网络超时断定业务未生效。
|
||||
- WAITING 超过总截止或最晚开始时间:FAILED。
|
||||
- 回收再次锁定队列、任务、尝试并读取数据库时间,与续租/完成串行化;多个节点不能重复释放许可或重复终结事件。
|
||||
|
||||
此处的安全回收不是完整重试引擎;IDEMPOTENT 的自动重试和策略退避仍是 P3 工作。
|
||||
|
||||
## 6. 连接保护与当前边界
|
||||
|
||||
当前节点上限 128 条 Worker 连接;每连接入站队列 4 帧、出站队列 8 帧,派发保留 ACK 缓冲空间,每秒最多发起 4 次新派发尝试。读空闲期限 60 秒、写期限 5 秒、单个数据库控制操作期限 8 秒。慢消费者导致连接关闭时,已提交状态仍由稳定身份恢复。
|
||||
|
||||
这些是有界的开发基线,不代表经过容量压测的生产参数。当前同队列操作使用较粗的行锁协调,吞吐与公平性需要 P6 按负载验证。服务退出会显式关闭被 HTTP Upgrade 接管的连接;断开不会直接撤销外部已发出的请求。
|
||||
|
||||
运行中取消、SDK 自动重连/续租、非协作处理器处理、完整 WS JSON Schema、凭据轮换和多节点进程级故障演练尚未全部完成。实际证据见 [P2 服务端阶段记录](../reports/phase-2-server.md)。
|
||||
Reference in New Issue
Block a user