-
背景
一个业务往往由多个子业务(本地或分布式)组成,每个子业务都有可能失败,最终导致业务失败。如何在失败后快速、正确的恢复业务是本文讨论的内容。 -
启发
大型软件安装的时候,都会分步完成,首先会检测环境,必要的依赖是不是已经安装,然后在一步一步安装子模块,如果哪个模块失败了,则会提醒用户处理,处理完了再重新打开安装程序,则会从失败的模块继续安装。受次启发,感觉我们的业务,也可以如此实现。 -
目标
- 幂等:对于同一输入的多次调用,已经执行的子业务不会在重复执行
- 可查询:对于每个子业务执行的结果,应该是可查询的;成功的,失败的,处理中的。
- 可监控:对于每个子业务,能监控其状态,在出现错误时能及时通知开发者
-
实现
对于一个业务,应该提供三个接口,主接口,执行中处理接口,查询结果接口-
主接口:
- 业务定义三种状态,执行中,成功,失败;定义唯一业务编号,可以使用该编号查询业务的状态
- 业务开始前,先查询业务状态,如果是失败或不存在,则记录状态为执行中,记录业务编号
- 每一个子业务开始前,先查询子业务状态,如果是失败或不存在,则记录状态为执行中中、记录业务编号;然后执行,并依据执行结果修改状态
- 如果子业务失败,则修改子业务和业务状态为失败,并终止流程
- 如果子业务为执行中,则根据后续子业务的依赖关系,来判断是否继续执行,最后修改业务状态为执行中
- 如果子业务都执行成功,则业务状态为成功
-
执行中处理接口
- 开启定时任务,查找执行中的业务,使用主接口保存的数据,从主接口第三步开始往后执行
-
查询结果接口
- 使用业务编号来查询业务执行结果
-
-
总结
- 对于业务或子业务的数据和状态,不一定要用建表,专门来存储。实际上大多数业务都比较简单(单个子业务),可以直接使用业务实体表上的状态。业务编号也是同样的道理,业务编号的作用,主要是为了查询状态,可以用实体表上的字段标识。例如商户支付进件业务,子业务就是掉三方的进件接口。业务状态和子业务状态,就可以用商户表的进件状态字段,业务编号可以用商户号。