在后端开发中,大家是否有遇到如下类型的开发场景
在以往的开发过程中,可能更多的直接使用数据库、定时任务、消息队列等作为基础,来解决上面的问题。然而即便如此,在代码开发中,也会有很多代码跟业务无关,比如 外部服务低可靠性情况下的重试,多异步事件下的程序逻辑组织等。最终会影响开发效率,并且可能会降低代码后期的维护性。
针对上面的场景,抽象为 工作流 模式的话,可以减轻开发成本以及维护成本
定义:指业务过程的部分或整体在计算机应用环境下的自动化。是对工作流程及其各操作步骤之间的业务规则的抽象、概括描述。
主要解决的问题:为了实现某个业务目标,利用计算机在多个参与者之间按照某种预订的规则自动传递问文档、信息或者任务。
工作流通常适用于,有状态的、异步、长时间执行等特性的业务场景,比较典型的场景包括
工作流框架还是比较多的,按照语言分类的话,有
在业务模块当中按规则编写 Workflow 流程以及其具体的 Activity,并注册到 worker 当中,启动 worker 外部⽤户触发 Workflow,Temporal 编排 workflow 形成⼀系列的 task 送到队列中,worker 去队列取任务,执⾏后将结果返回给Temporal。
举一个银行的流程示例:
由四部分组成Start、Temporal Server、Worker、Bank
具体的流程描述:
workflow 即表示工作流,在 Temporal 中,工作流是由函数或对象方法来实现(工作流样例见下文)。
一个 workflow 通常完成一个业务目标。同时,当多个 workflow 中,有同样的处理流程时,可以封装为一个子的workflow,来达到代码复用的目的。
启动Workflow的时候,可以设置这个Wrokflow的执行超时时间,以及失败后的重试次数、任务队列名等参数,来更好的满足业务需求
支持的配置参数如下:
workflowOptions := client.StartWorkflowOptions{
ID: "hello_world_" + uuid.New(), //用于业务级别标识。不可能有两个一样的workflowId同时工作
TaskQueue: "hello-world", //活动任务队列。让收到任务的 Worker 知道下一步要执行哪一段代码。 Workflows(工作流)只能使用一个任务队列
WorkflowExecutionTimeout: 10 * time.Minute, //Workflow的最大运行时间,包括失败后重试的时间。默认无限制
WorkflowRunTimeout: 3 * time.Minute, //单次运行的时间。默认值为 ExecuteTimeout
WorkflowTaskTimeout: 10 * time.Second, //从Worker从任务队列拉取到Workflow任务,到Worker开始执行Workflow的时间。如果超时,Server会认为Worker已经挂掉,会重新调度该Workflow给其他Worker,默认值10s
RetryPolicy: &temporal.RetryPolicy{ //重试策略
InitialInterval: 30 * time.Second, //初始间隔 描述:第一次重试前,需要等待多久。无默认值。如果提供重试策略,则必须提供一个值。用例:这用作退避系数乘以对抗的基本间隔时间
BackoffCoefficient: 2, //退避系数 描述:退避系数,表示多次重试时,下次等待的时间是上次的多少倍。默认值设置为 2.0。回退系数为 1.0 表示重试间隔始终等于初始间隔。用例:使用此来增加重试之间的时间间隔。通过具有回退系数,前几次重试相对较快地发生以克服间歇性故障,但随后的重检将发生越来越远的距离,以考虑更长的持久中断。使用 maximum interval 最大间隔选项来防止系数过多地增加重试间隔。
MaximumInterval: 5 * time.Minute, //最大间隔 描述:下次重试时,最大等待时间。默认值:100*初始等待时间。用例:这对于大于 1.0 的系数很有用,因为它可防止间隔以指数级无限增长。
MaximumAttempts: 1, //最大重试次数 描述:默认值:0,表示无限重试,但在大多数情况下,建议依靠执行超时来限制检索的持续时间,而不是此选项。
NonRetryableErrorTypes: []string{"TemporalTimeout:StartToClose"}, //表示Workflow遇到哪些Error后,不再进行重试
},
}
一个Workflow,可由 命名空间,Workflow Id 和 Run id 唯一标识
启动Workflow的时候,可以指定一个ID,这个ID一般采用业务级的ID,如一个要处理的客户的ID或订单ID
启动Workflow的时候,可以设置为定时启动。
注意。如果到了下次运行Workflow的时候,但上次的Workflow还没执行完(可能任务执行耗时长,或由于失败后重试等原因),会跳过下次运行Workflow
we = client.GetWorkflow(workflowID)
var result string
we.Get(ctx, &result) // 获取是阻塞的
Activities可以理解为一个业务操作单元。在Workflow执行过程中,会将Activity放入消息队列,由其他Worker获取后,执行该Activity,并将结果再返回给Workflow。
和Workflow的重试策略完全一致
如果一个Activity运行时间较长,最好设置一个心跳间隔超时。这样当执行Activity的Woker挂掉时,Server可以及时知道
三种方法可供使用
根据 SKD 的 api workflow.GetVersion() 分支运行的新旧工作流代码
对于正在运行的 WorkflowExecution,可以发送携带参数的信号,Workflow中可以等待或根据条件处理信号,动态控制工作流的执行逻辑。示例
考虑工作流执行事件历史大小限制需要对父 Workflow 做拆分。希望将每个子工作流执行视为单独的服务。示例
类似Go的select,允许goroutine等待多个通信。一个select块直到它的一个case可以运行,然后执行。如果多个已准备就绪,则随机选择一个。
是一个单点网关,提供 Proto API。可以接受来自浏览器、tctl(Temporal的命令行工具)、以及业务方的调用请求。(主要用于接口限速、授权认证、校验和请求路由)
用于记录Workflow的执行状态,并且支持横向拓展。
用于管理任务队列,及任务分发,并且支持横向拓展
用于维护拷贝队列和执行一些Temporal服务自己的Wrokflow。
保存了用于分发的任务信息、以及Workflow的执行状态、命名空间元数据,前端可视化配置
常用 API 使用示例代码
Temporal 官网提供了Web UI组建。可以通过浏览器查看Workflow的执行状态和结果
点击此处展开...
点击此处展开...
进入Web UI首页,即可查看最新的工作流执行状态列表
点击 Workflow ID,可以查看单个workflow的执行详情。
如下下图显示,可以看到Workerflow的:开始时间、结束时间、执行结果状态、输入参数、输出参数、...