Application(Worker 和 Client)
查看 MarkdownDex 应用就是你部署的代码。它包含两部分:
- Worker 承载 Flow 定义。Dex 分配工作时,它运行 WaitFor、Execute 和 RPC handler。
- Client 启动 Flow、调用 RPC、读取 Attribute 和搜索 Flow。见 Client。
一个进程可以只运行 Worker,只运行 Client,也可以两者都运行。
与其他组件的关系
Worker 和 Client 连接 Dex Server(server-zd)。每个 Worker 都是拉取模式 Worker:它主动向 server 建立出站任务 stream,从不监听调用。因此 Worker 不需要开放入站端口,可以运行在 NAT 或防火墙后面。
Dex 把所有 Flow、SubFlow、Step 和 RPC 调用都发给你的 Worker,不需要配置 Worker 地址。Dex Web 或 dexcli 启动的 Flow 也在你的 Worker 上运行。
Worker 启动时,可以把它的 Flow 的 Flow Definition Graph 发布到 server。Dex Web 从 server 读取它们,画出每个 Flow。
启动 Worker
给 Worker 配置 server 地址。Client 也只需要 server 地址。你还可以设置 pull 选项,调整任务容量、注册和关闭行为。
各 SDK 参考都有可运行的启动示例:Go、Python、Java、TypeScript 和 Rust。
容量和关闭
Worker 为每个任务槽位建立一个 stream。Dex 只把任务发给空闲的槽位,所以 Worker 不会因为容量不足而拒绝工作。没有 Worker 接手的 Step 会在持久任务队列中等待。RPC 如果在限定时间内没有 Worker 接手,就会失败。部署时要优雅地停止 Worker,让正在运行的任务完成。
就绪检查、路由、容量、关闭和网络设置见英文的 Workers and the task queue。
在生产环境中运维
Flow 不再推进或失败时,按英文的 Troubleshoot a Flow run 排查。
Flow 代码版本控制
Dex 不会重新执行你之前的 Step 代码来决定 Flow 下一步做什么,所以部署改过的代码不会引起重放错误。但你仍要保证正在运行的 Flow 在部署后继续正常工作。它们可能遇到业务规则变了、Step 实现没有了、RPC 改名了,或者数据不兼容。
在 Flow 启动时锁定业务行为
Flow 启动时,把一个业务版本值持久化下来,例如放在一个 Attribute 或启动状态的字段里。之后按这个保存的值分支,而不是按当前处理调用的 Worker 版本分支。这样已有的 Flow 保持旧行为,新 Flow 在部署后使用新行为。
如果改动会影响决策、支付规则、重试策略、截止时间或其他客户能看到的含义,就使用这种做法。只发布新代码不算版本控制,因为长时间运行的 Flow 之后可能会调用新部署的 Worker。
以增量方式演进数据与契约
只新增可选字段。读取数据的代码要能处理旧运行没有设置的字段,也要忽略新组件发来的未知字段。缺少的字段要有安全的默认值,已有字段的值要保持原来的含义。如果输入或输出的格式必须不兼容地改变,就新建一个 Step type 或 RPC 名称,不要悄悄修改旧的。
在旧 Flow 结束前保留旧定义
只要还有正在运行的 Flow 可能调用某个 Flow type、Step type 或 RPC,就不要删除或重命名它的实现。把新定义和旧定义一起部署,只让新版本的 Flow 使用新定义。旧实现要一直保留,直到重试和经过批准的 Time Travel 恢复都不再需要它。
滚动部署期间,如果一个 Worker 缺少被请求的 Step 或 RPC,它可以把调用交给另一个有它的 Worker。这样不会消耗 Step attempt。见英文的 Routing and availability。
删除旧定义之前,先搜索旧的 Flow type,确认没有正在运行、等待、重试或可恢复的已结束 Flow 还需要它。把搜索结果记录在变更记录里。具体查询取决于你的搜索字段。可以先按 Flow type 搜索:
dexcli flow search --query 'FlowType = "OldFlowType"'
只有在搜索结果为空,或者剩下的每个 Flow 都有明确批准的退役计划时,才删除旧代码。