使用flowable工作流框架时,为了将业务系统和工作流服务进行解耦,将工作流服务独立为一个核心模块,不涉及业务逻辑的处理。凡是需要业务数据的地方都通过配置化的形式请求业务系统,具体配置可参考
<serviceTask id="serviceTask1" name="task1" flowable:delegateExpression="${remoteHttpServiceTask}">
<extensionElements> <flowable:field name="requestUrl">
<flowable:string><![CDATA[http://baseweb-service/testXml]]></flowable:string>
</flowable:field>
<flowable:field name="requestBody">
<flowable:string><![CDATA[{"age":"2"}]]></flowable:string>
</flowable:field>
<flowable:field name="requestMethod">
<flowable:string><![CDATA[POST]]></flowable:string>
</flowable:field>
</extensionElements></serviceTask>
通过serviceTask的形式自定义相关配置,请求业务系统,获取对应的数据。这样,工作流服务和业务系统就完全解耦了。当然,这里是采用http的形式进行跨服务调用的,也可以通过redis订阅、消息队列等形式进行跨服务请求调用,这样的设计是不是很巧妙呢?
但是,马上就面临问题了。。。
有时候serviceTask请求失败了怎么办?网络不通畅怎么办?业务数据需要进行操作回滚怎么办?比如,某个请假流程中,业务系统中请假表单的状态为初始化状态,首先工作流服务请求业务系统更改请假状态为请假中状态,接着工作流服务告知业务系统执行具体逻辑(此处笔者采用的是http调用),但是业务系统执行出错了或者出现了其他的错误,工作流服务岂不是要请求业务系统恢复请假状态或者更改为异常状态(实际情况可能比这个复杂的多),这些属于流程图之外的异常考虑范围了,毕竟太多的serviceTask不可能所有的都加上补偿机制,怎么办呢?
有人立马会想到补偿机制,增加一个补偿任务不久ok了吗?但是我的业务功能被分割成了众多单独的模块(即很多的serviceTask),如果每一个服务都需要这样的一个补偿机制,那么我的流程图就会变得很臃肿,暂时放弃这种选择!最后想了一个办法,统一的将这些需要回滚的数据进行入库操作,后台线程定时查询数据库完成这些补偿机制。(当然,大家如果有很好的办法,可以留言讨论)
serviceTask部分代码如下:
@Override
public void execute(DelegateExecution delegateExecution) {
log.info(String.format("服务任务开始执行,ExecutionId--->%s", delegateExecution.getId()));
if (Objects.isNull(requestUrl) || Objects.isNull(requestMethod)) {
log.error("requestUrl or requestMethod is empty");
return; }
String urlStr = parseExpression(requestUrl, delegateExecution, serviceConfig::processHttpUrl);
String methodStr = parseExpression(requestMethod, delegateExecution, Function.identity());
String jsonStr = parseExpression(requestBody, delegateExecution, Function.identity());
try {
switch (methodStr) {
case MethodType.GET:
ResponseEntity<String> getResponseEntity = httpUtil.sendGetMethod(urlStr, jsonStr, String.class);
handleResponse(getResponseEntity, delegateExecution);
break; case MethodType.POST:
ResponseEntity<String> postResponseEntity = httpUtil.sendPostMethod(urlStr, jsonStr);
handleResponse(postResponseEntity, delegateExecution);
break; default:
log.error("request method not support");
}
} catch (BpmnError e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
throwExceptionWhenFail(delegateExecution, Collections.EMPTY_MAP);
}
}
当然,这个只是解决了某些需要回滚或更新业务数据状态的问题,目的是为了使流程在可控范围之内,但是,http调用出错呢,业务数据和工作流服务之间突然网络不通畅,或者出现了大量丢包超时的现象,直接上图
也就是serviTask1执行的时候出错了?
serviceTask2要不要继续执行,默认情况下工作流会在task1中抛出exception,若无任何异常捕获机制,会默认重试三次,然后方法结束(但是流程不会终止,serviceTask2不会执行)
这个地方就分多种情况了。
1.捕获异常
1.1 流程图捕获这个异常。自己定义边界异常捕捉事件,捕获到异常时,流程图走向其他的分之
1.2 代码中捕获异常。但是捕获异常后怎么办呢?
抛出异常,会走默认重试三次,然后方法结束(但是流程不会终止,serviceTask2不会执行)的逻辑
不抛出异常,servicetask2继续执行(serviceTask2有部分数据依赖serviceTask1),后面还是会报错,一发不可收拾
最终解决方式:手动终止流程
对,直接悬崖勒马,捕获异常不抛出并终止流程,这样serviceTask2 就不会执行了,同时也不会重试三次了(重试三次也可以通过flowable相应配置更改,当然有时候需要这个配置,本文中不希望它进行重试)
但是,终止流程这个方法有很多坑,最起码百度上面没有一个可以讲清楚的,详情通过下一篇文章讲解
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。