目录
2. Service Task fetch and lock
摘要
假如你是希望学习BPMN,初次想要了解Camunda来做工作流引擎,那么欢迎收藏这篇博客。因为我会介绍BPMN最重要的一些元素,还附加了完整BPMN设计源文件和用来调试的Camunda REST Api的Postman脚本。
源文件地址:Camunda-BPMN - Repos (azure.com)
对BPMN完全没有了解的话请参考我之前的博客:Camunda BPMN_郭麻花的博客-CSDN博客
这次我们通过一个常见的业务场景:订单流程来说明Camunda在实践当中是如何工作的。
基于BPMN的软件设计思想
BPMN(Business Process Modeling Notation,即业务流程建模符号),是一种流程建模的通用和标准语言。在学习BPMN之前需要先意识到:
- BPMN是一种能被程序识别并执行的语言,而不是简单的流程图;
- BPMN流并不关心具体实现(系统可以采用微服务或是单体,异步或是同步,或者任何实现方式);
- BPMN可以通过Camunda这类的流程引擎来执行;
- Camunda流程引擎只会向外界通知当前流程所处的状态,并接收程序的反馈,做出响应。
这种开发方式要求我们将软件服务分为流程调度与任务执行两种类型。
流程调度程序需要配合Camunda来实现任务有序正确的执行,比如当流程调度程序接收到Camunda通知,来到“订单支付成功,给用户发送通知” 这一步时,它将从当前workflow获取该订单流程的状态信息,比如订单号,之后可以通过Api调用,或者消息队列等等任何方式去完成用户通知这一任务。
而任务程序的设计将更加单纯,它不需要,也不应该去考虑workflow前后所发生的事情,那是在设计BPMN时应该去调度协调的事情。比如“订单支付成功,给用户发送通知” 任务,它要做的事情就是根据订单号,拿到需要的订单信息和支付成功通知的内容模板,给用户发送信息。
简单来说,流程调度服务:“让你干啥你干啥”;任务服务:“让我干嘛我干嘛”。
电商订单流程业务场景
电商平台都支持在线下单功能。我们就用以下业务要求为背景来设计一个Camunda workflow:
- 用户可以在页面选购商品,并点击提交下单。
- 系统通过短信,微信等渠道发送下单成功通知。
- 用户需要在30分钟内完成付款,超时未付款则订单自动取消,并且发送取消通知。
- 若用户下单后15分钟未付款,则发送待付款提醒。
- 用户付款成功之后,发送付款成功通知并等待配送。
- 在配送完成之前,用户可以随时手动选择取消订单,系统后台需要取消订单并退款。
思考题:假如之后业务要求开始配送之后的订单不能提交退款申请怎么办?
基本订单流程BPMN设计
1.最基本流程设计
最基本的订单流程应该是这样的,当用户提交订单时便触发最左边的Start Event,一个workflow实例就被创建了出来。
1. BPMN中带有齿轮的长方形格子代表能够被自动执行的任务,叫做Service Task。第一个任务是“Create Order”,可以是由流程调度程序通知订单服务去创建一个订单,订单服务可以选择写入数据库并更新缓存等任何事情;甚至可以什么也不做,直接回复给workflow当前任务已完成也是可以的,流程引擎只负责通知和接收程序反馈,并不关心实现。
2. “Pay for order”和“Pickup”这类任务是User Task,它们并没有一个明确的完成时机,当用户在某个时间完成支付之后,需要由程序去告知workflow当前用户任务已完成,此时workflow会自动继续往下执行。
要善于使用workflow当中的变量,它们可以存放当前workflow的重要信息并一直向下传递,在BPMN中为任务使用合适的Input和Output Parameters非常重要!
2. 添加超时未付款自动取消功能
我们只需要在workflow的“Pay for order”阶段加一个Timer boundary event,并且把触发时间改为30分钟之后就可以了。当30分钟后 workflow仍处于Pay for order阶段时,实线圆圈的Timer表示Interrupting模式,它触发时将结束当前Task并且转向执行下方的“Order Automatically Canceled”任务。
3. 添加15分钟付款提醒
只需要添加一个虚线代表的Non-Interrupting Timer,15分钟之后触发,它触发时不会结束当前的Task,而是通过分裂Process token到下方的“Send Order Unpaid Notification” ,付款提醒会被自动发送,而workflow会继续等待用户操作。
4. 添加用户取消订单事件
在“Pay for order”和“Pickup”上添加一个Error Event,表示在等待付款和配送阶段,workflow将会接收程序发来的“Order Manually Canceled”事件,当该事件发生时,应当立即结束当前任务,执行订单取消相关的任务。
进阶订单流程BPMN设计
前面介绍了一个基本的BPMN流程的设计思路,接下来我们基于业务要求,设计一个更清晰,低耦合的BPMN流程。
1. 使用并行网关执行任务
我将订单创建后,配送完成前这一阶段的所有事件与任务划分到了同一个子流程当中,后面会介绍。这里将“发送订单创建成功通知”和“等待付款”两个任务用并行网关分开执行,因为从业务上来讲,发送通知失败不应该影响用户付款,所以这两个任务一定不是串行执行的。
这里为“Send Order Created Notification”加了一个超时自动结束的Timer Event。这因为子流程会因为包含存活的Process Token而无法结束。假如发送通知这类的边缘任务失败,程序也应该能正常往下执行。当然,除了使用BPMN的方式保证流程正常执行以外,也可以通过程序的方式来保证每个Service Task不论结果如何都被结束。
关于Process Token的概念可以参考:BPMN Process Token与Gateway——Camunda Workflow 开发实践
2. 将具有相同事件分支的任务合并为子流程
之所以将上述服务添加到同一个Sub Process当中是因为它们具有相同的流程分支,即订单取消。
根据业务要求,配送完成前的任何阶段用户都可以选择取消订单,或者超时自动取消订单。因此,通过将上述任务合并到同一个子流程当中,并且为该子流程创建统一的Error Event处理程序更为合理。
Tips:Error Event可以携带信息到workflow当中,前提是需要设置它的Code Variable或Message Variable。
3. 使用Event Sub Process
如图所示,我们可以在子流程当中继续添加子流程。在此我将之前添加的两个Timer触发器改成了事件子流程。
事件子流程同样分为Interrupting和Non-Interrupting两种模式,在将Timer划分到事件子流程之后,我们必须依靠workflow当前的状态来判断订单是否已经支付,以确定下一步状态。
因此我们需要在订单支付后,将“已支付”状态保存到当前workflow实例当中,因此我为“Pay for order”任务添加了一个Output Parameter, 我们在结束Task时可以传递任意参数,但只有当这些参数在Output当中声明后,它们才能被添加到workflow当中,并在之后的流程中使用。
在上面这种情况, “Pay for order”任务结束之后,IsPaid参数可以确定是True。这里使用 ${execution.getVariable('IsPaid')} 是为了从代码传递过来的参数中获取。
4. 将配送完成任务改为Message Event
Message Event代表一个通知的到来,或许订单配送完成并不是靠人为操作,而是依赖于IoT设备,因此我们可以将原先的“Pickup” User Task替换为Message Event(见上图信封图案),只有当系统收到配送完成的消息时才会继续往下进行。
使用Camunda REST Api调试Workflow
Camunda常用接口的Postman文件我已经放在开头的代码仓库里了,可以采用Basic方式身份认证。
1. 获取Service Task
2. Service Task fetch and lock
3. Complete Service Task
可以看到此时处于等待订单支付,且发送订单待支付提醒,两个任务同时进行阶段。而上面的“Send Order Created Notification” 在我截图时已经超时结束了。
4. 手动取消订单 Handle BPMN Error
此时因为收到订单取消事件,子流程当中的一切活动(Activity)都将被结束,workflow转向“Order Manually Canceled”处理程序。
还有一些接口,这里就不再一一列举了,大家可以到Camunda-BPMN - Repos (azure.com)学习下载。