刨开同伙的shit山代码

127 阅读2分钟

一,背景

新需求来了,在旧代码上处理新需求,今天就来刨一刨同事小伙的屎山。

二,代码逻辑

image.png 如图所示,系统若干服务的操作影响的数据要根据类型推送到下游服务B、C、D等,服务O是做专门转发的服务,根据策略进行转发。

三,分析

1,服务A和O的交互参数

交互参数不是实体,而是业务主键ID,组装实体的逻辑不是放在服务A侧,而是放在O里,这样做的原因是方便重试,见下图

image.png

如果推送不成功,左侧的补偿程序会执行,这个时候只需要传业务主键及类型即可触发。

但是,但是,但是

没考虑数据的时态,因为组装参数是以执行瞬间数据库的数据为准的,在这样的场景下就有问题:

d-1d -1d
推送账单下单失败用户支付,更新状态重试推送状态不应该是支付,应是下单

怎么办,改呗,组装参数增加重试时间这个参数,,,,,问为啥之前没出问题,因为这个项目只到提交测试阶段,我就接手了,,,,,,,,

2,事务问题

我把A、O写成代码,就一目了然了

class AService {
    @Resource
    private Oservice oService;
    
    
    @Transaction(Rollback = Exception.class)
    publict void deal(){
        String bizNo =  "xxx";
        //xxxx业务逻辑
        oService.sendB(bizNo);
        CompletableFuture.supply(()-> oService.sendC(bizNo));   
    }
}

看出问题来了么,看出几个问题了?

当前事务没有提交,oSerivce里sendB、sendC组装参数查不到数据,不管是同步调用还是异步调用,都没办法读取当前事务未提交的数据,那如何处理? 改MQ,确实,还解决了分布式事务问题,由于sendB、sendC属于通知类操作,和当前操作的优先级相比,输入不入流的小操作,当然不能没有,所以用MQ,或者本地事务表都能解决,当然本地事务表要配合扫描定时任务。

image.png

如图,操作和写本地事务表在一个事务里,发送交由重试任务来解决。