场景
调用第三方接口扣减积分,本地落地积分扣减明细。
问题
若第三方扣减积分成功,本地落地失败怎么办?
解决方案
开始想着与第三方扣减会传入一个扣减流水号,然后用消费程序来跟第三方对接,如果本地落地失败,那么让消息重发,用同一个流水号做幂等去扣减。并不是这种逻辑是错的,而是思想是错的,用消息队列解耦是因为怕第三方接口调用慢,影响了微服务的效率,所以用异步,而不是为了靠重推来做幂等,所以解决方案如下。
方案1:同步模式
假如我们不用异步模式,直接微服务调用接口来扣减,那么我们需要用如下的逻辑。
//1、插入一条流水扣减记录,标识状态为正在扣减
//2、调用第三方接口扣减,若接口返回扣减失败,则设置该条流水的扣减记录为扣减失败
//3、若超时,则设置扣减记录为扣减超时
//4、开启事务
//5、本地落地扣减明细
//6、提价事务
//7、若4,5,6失败,则设置该条流水的扣减记录为本地落地失败,否在设置扣减成功
这里必须在第1步骤需要先插入一条扣减流水。然后后台起一个批处理程序去遍历扣减流水,如果有扣减超时或者本地落地失败的就直接根据流失去查该流水的扣减记录,维护回来,如果扣减失败的则不用理。
方案2:异步模式
异步模式是微服务登记一条扣减消息到消息队列,然后消费程序来去跟第三方对接扣减,其实步骤跟方案1差不多,只不过不需要后台起一个批处理程序。
//0、查询该扣减流失是否存在,若已存在则查看扣减状态,若为本地落地失败或者扣减超时则根据该扣减流失去调用第三方接口查询状态,若状态为成功则重新执行4,5,6,7,8
//1、插入一条流水扣减记录,标识状态为正在扣减
//2、调用第三方接口扣减,若接口返回扣减失败,则设置该条流水的扣减记录为扣减失败
//3、若超时,则设置扣减记录为扣减超时
//4、开启事务
//5、本地落地扣减明细
//6、提价事务
//7、若4,5,6失败,则设置该条流水的扣减记录为本地落地失败,否在设置扣减成功
//8、若本地落地失败或者扣减超时则消费状态返回false,该条消息重新消费。
这种模式多了前面0步骤和后面的8步骤来代替后台批处程序。