京东零售/asycTool组件工作流程解析

339 阅读5分钟
该框架目前正在 **京东App后台** 接受苛刻、高并发、海量用户等复杂场景业务的检验测试

asyncTool特点

解决任意的多线程并行、串行、阻塞、依赖、回调的并发框架,可以任意组合各线程的执行顺序,带全链路回调和超时控制。

其中的A、B、C分别是一个最小执行单元(worker),可以是一段耗时代码、一次Rpc调用等,不局限于你做什么。

该框架可以将这些worker,按照你想要的各种执行顺序,加以组合编排。最终得到结果。

并且,该框架 为每一个worker都提供了执行结果的回调和执行失败后自定义默认值 。譬如A执行完毕后,A的监听器会收到回调,带着A的执行结果(成功、超时、异常)。

根据你的需求,将各个执行单元组合完毕后,开始在主线程执行并阻塞,直到最后一个执行完毕。并且 可以设置全组的超时时间 。

该框架支持后面的执行单元以前面的执行单元的结果为自己的入参 。譬如你的执行单元B的入参是ResultA,ResultA就是A的执行结果,那也可以支持。在编排时,就可以预先设定B或C的入参为A的result,即便此时A尚未开始执行。当A执行完毕后,自然会把结果传递到B的入参去。

项目地址

gitee.com/jd-platform…

基本组件

worker: 一个最小的任务执行单元。通常是一个网络调用,或一段耗时操作。 T,V两个泛型,分别是入参和出参类型。 譬如该耗时操作,入参是String,执行完毕的结果是Integer,那么就可以用泛型来定义。 多个不同的worker之间,没有关联,分别可以有不同的入参、出参类型。

image.png callBack:对每个worker的回调。worker执行完毕后,会回调该接口,带着执行成功、失败、原始入参、和详细的结果。

image.png wrapper:组合了worker和callback,是一个 最小的调度单元 。通过编排wrapper之间的关系,达到组合各个worker顺序的目的。 wrapper的泛型和worker的一样,决定了入参和结果的类型。 下面定义一个测试的例子为一个最小单元worker的实现:

image.png WorkerWrapper类是对于worker及callback的封装

核心内容解析:

private String id;

每个Wrapper的唯一标识

private T param;

worker将来需要处理的入参,初始化时传入

private IWorker<T, V> worker;

private ICallback<T, V> callback;

初始化时传入,对于工作内容和回调内容的实现

private List<WorkerWrapper> nextWrappers;

初始化时定义该wrapper的下游wrapper,可为多个

private List dependWrappers;

该wrapper的强依赖集合,想要执行该wrapper必须等待定义的其他wrapper执行完成,已达到如下的工作流程,3必须等1/2完成才能执行,

初始化时可通过定义ismust为false关闭该wrapper对其他wrapper的强依赖,使得1/2其中一个执行完成3就可以运行

private AtomicInteger state = new AtomicInteger(0);

private static final int FINISH = 1; 已完成

private static final int ERROR = 2; 异常

private static final int WORKING = 3; 工作中

private static final int INIT = 0; 初始化状态

标记该wrapper的状态,是否已经被处理过了,譬如已经超时返回false了,后续rpc又收到返回值了,则不再二次回调

private Map<String, WorkerWrapper> forParamUseWrappers;

用于存放所有wrapper的id和wrapper映射,在V1.3版本可使用id直接获取存放在map中的wrapper的执行结果,如allWrappers.get("inventoryFoundWorker").getWorkResult()。

private volatile WorkResult workResult = WorkResult.defaultResult();

用来存放该wrapper临时的执行结果

private volatile boolean needCheckNextWrapperResult = true;

是否在执行自己前,去校验nextWrapper的执行结果

如上图,在4执行前,可能3已经执行完毕了(被2执行完后触发的),那么4就没必要执行了。该属性仅在nextWrapper数量<=1时有效,>1时的情况是不被允许不执行的的(将逻辑修改是可以对其下游的执行状态进行判断 private boolean checkNextWrapperResult() {

boolean state;

if (nextWrappers == null ) {

return getState() == INIT;

}else{

for(WorkerWrapper workerWrapper : nextWrappers){

state = workerWrapper.getState() == INIT;

return state && workerWrapper.checkNextWrapperResult();

}

}

return true; } ,但是无法知晓与其并行的其他wrapper是否需要该wrapper的运行结果)。

wrapper创建:

image.png

wrapper在build的时候会遍历其依赖wrapper,并在其依赖的wrapper将自己注入到依赖的wrapper的nextWrapper中。

如下为一个测试wrapper的创建:

image.png 整个wrappers开始的入口,不传入自定义线程池则默认程序中定义的线程池。

image.png futures用于存储各wrapper的返回值。

CompletableFuture.runAsync() 创建异步任务,开始执行并行的wrapper各自任务.

image.png 非开头wrapper需要通过(doDependsOneJob或者doDependsJobs)判断其依赖的wrapper是否完成, 依赖分为强依赖与弱依赖,强依赖一个wrapper,执行当前wrapper的必要条件是wrapper执行完成,成功执行没产生异常,剩余时间大于0,否则快速失败进行下一步,弱依赖则是不管依赖的wrapper是否完成,只要时间大于0,上游没产生异常则继续执行。

fire() 》》》 workerDoJob()

image.png 在同步阻塞执行workerDoJob() 的时候会去大量判断当前wrapper的状态(info,working,finish),在执行action()前判断是否处于init状态,如果不是则说明正在被执行或者已完成,则直接返回,如果不是则通过compareAndSet将info替换为working。在执行成功后判断是否处于working,如果不是则时间返回,不再执行过多的操作,如果不处于working则同样通过compareAndSet将working替换为finish,并将wrapper的result属性值传入worker的执行返回结果。

完成后执行下游wrapper,beginNext(executorService, now, remainTime);

image.png 首先通过上游wrapper执行时间计算出剩余的工作时间,再执行下游的wrapper。

下面列一个具体的任务及其工作流程图:

image.png