异步调用(1)

一、场景分析

1.适用场景

适用于被调用者执行的为耗时操作、且即时性要求不高,调用者执行速度有较高要求的情况。

2.场景分析

1、被调用者和调用者是否在同一个应用(Web App)中?
分析:大多数情况在,但应该支持远程调用。
2、调用者和被调用者是否连接同一个数据库?
分析:在需要连接数据库执行操作的情况,一般连接同一个数据库,但存在需要链接不同数据库的情况。
3、是否需要做事务补偿机制?
分析:of cause.考虑以下两种策略:
(1)被调用者执行失败,则进入错误队列,人工修正问题后,重试;不回滚调用者。
(2)被调用者执行失败,则回滚调用者。
策略1人工干预成本高,如果错误量巨大,则人工运维成本奇高;而且存在错误无法修正的情况,如:调用者为下订单,被调用者生成出库单,没货了。
再看策略2,一般情况,调用者发起异步调用后会提示提交成功,如果此时再回滚,用户交互设计会比较复杂。但应支持这种模式。
结论:
支持两种模式:
(1)直接提交模式:调用者直接提交事务,被调用者失败不影响提交者,失败信息记录在日志中,提供重试机制。
(2)TCC模式:调用者设置状态位,事务提交后状态为“预提交”,被调用者提交后改为“提交”;调用者提供回滚逻辑,被调用者失败后,调用回滚逻辑,修改状态为“取消”。
调用者决定采用哪种事务补偿机制。
4、是否依赖Spring Bean工厂?
依赖Spring Bean工厂将降低适用范围,应考虑没有Spring Bean工厂的情况。
但考虑实际情况,大多数应用场景中是有Spring Bean工厂支持的,而且Spring Bean工厂可以解决复杂的Bean之间依赖关系的问题。
考虑为80%的情况设计的原则,优先支持依赖Spring Bean工厂的情况。
5、是否要取回结果?
存在需要取回结果的场景,比如:需要将异步调用生成的出库单据号返回给订单系统建立关联;需要将耗时生成的报表地址返回。
但这些场景都有其他更合理的返回结果方式。

二、功能设计

1. 定位被调用者

同时支持本地调用和远程调用,通过以下uri定位被调用方法:

//本地调用,Spring中id为userService的bean的registerLog方法
String target1 = "userService.registerLog";
//远程调用,通过rpc-server-alias获取远程调用配置实例
String target2 = "rpc-server-alias/userService.registerLog";
// service id中包含“.”,则认为是接口名/类名
String target3 = "cn.dragonberg.user.UserService.registerLog";
String target4 = "rpc-server-alias/cn.dragonberg.user.UserService.registerLog";

2. 调用方式

// 简单模式 1
void AsyncCall.invoke(String target,Object...params);
// 高级模式 2
AsyncCall asyncCall = new AsyncCallI(target,params){
    /**
     * 异步调用执行完成时被调用。
     */     
     public Object success(String token,Object result){
        // 接收调用结果,如将出库单号关联到订单号
     }
     /**
     * 异步调用失败时被调用。
     */     
     public Object rollback(String token,Throwable e){
        //处理回滚逻辑
     }
};
asyncCall.invoke();

猜你喜欢

转载自blog.csdn.net/stationxp/article/details/54891973