前言

xxl-job是一个分布式任务调度平台,其外围设计指标是开发迅速、学习简略、轻量级、易扩大、开箱即用。我部门大部分定时任务调度都是基于xxl-job,诸如报表统计、定时数据同步等。
明天的素材来源于某天产品经理想在定时同步报表数据的根底上,再减少一个手动触发报表数据同步的性能。即在报表页面上新增一个手动同步的按钮,触发该按钮就能够执行报表数据同步

需要剖析

1、保留定时同步性能,同时新增手动同步

2、手动同步的数据产生的成果要和定时数据同步的产生成果一样

解决思路

1、计划一、新建一个手动调用的controller,controller触发数据同步逻辑service

其实就是把写在xxl-job执行器外面的同步逻辑,再放到controller执行一遍

2、计划二、新建一个手动调用的controller,在controller外面间接触发xxl-job执行器

解决方案剖析

在原先的定时器场景,咱们为了防止定时器外面的同步逻辑还没实现,下次定时器就触发导致数据同步不精确,咱们在执行器外面做一些伎俩进行躲避,比方设置同步实现标记位等。
如果基于计划一,计划看似可行,其实存在潜在的坑点。即定时器执行的时候,手动刚好触发执行,或者反过来,手动触发的时候,定时器也执行了。这样就会导致数据同步执行屡次,导致数据不精确。

前面咱们调研了xxl-job,看到了xxl-job有提供restful格调触发执行器的性能,这个性能几乎就是为咱们量身定做,当手动调用的时候,触发执行器,因为执行的是执行器外面的调用逻辑,因而就会触发咱们为防止数据同步不精确所采取的伎俩

如何通过restful格调手动触发xxl-job执行器执行

其具体介绍能够查看官网,其链接如下

https://www.xuxueli.com/xxl-job/#6.2 执行器 RESTful API

本例的外围代码块

@RestController@RequestMapping(value = "xxl-job")@Api(tags = "xxl-job restful调度")@Profile("job")@Slf4jpublic class XxlJobController {    @Autowired    private XxljobClientHelper xxljobClientHelper;    @ApiOperation(value = "手动触发工作")    @GetMapping("/run")    public AjaxResult execute(){        String adminClientAddressUrl = xxljobClientHelper.getAdminClientAddressUrl();        String accessToken = xxljobClientHelper.getAccessToken();        log.info("adminClientAddressUrl:{},accessToken:{}", adminClientAddressUrl,accessToken);        ExecutorBiz executorBiz = new ExecutorBizClient(adminClientAddressUrl, accessToken);        ReturnT<String> retval = executorBiz.run(getTriggerParam());        log.info("retval:{}", JSON.toJSONString(retval));         // 200 示意失常、其余失败        if(retval.getCode() == 200){            return AjaxResult.success();        }        return AjaxResult.error(retval.getMsg(),retval.getCode());    }    private TriggerParam getTriggerParam(){        TriggerParam triggerParam = new TriggerParam();        // 工作ID//        triggerParam.setJobId(15);        // 工作标识        triggerParam.setExecutorHandler("demoJobHandler");        // 工作参数        triggerParam.setExecutorParams("手动触发工作");        // 工作阻塞策略,可选值参考 com.xxl.job.core.enums.ExecutorBlockStrategyEnum        triggerParam.setExecutorBlockStrategy(ExecutorBlockStrategyEnum.COVER_EARLY.name());        // 工作模式,可选值参考 com.xxl.job.core.glue.GlueTypeEnum        triggerParam.setGlueType(GlueTypeEnum.BEAN.name());        // GLUE脚本代码        triggerParam.setGlueSource(null);        // GLUE脚本更新工夫,用于断定脚本是否变更以及是否须要刷新        triggerParam.setGlueUpdatetime(System.currentTimeMillis());        // 本次调度日志ID        triggerParam.setLogId(triggerParam.getJobId());        // 本次调度日志工夫        triggerParam.setLogDateTime(System.currentTimeMillis());        return triggerParam;    }}

注: 代码中的demoJobHandler,就是执行器外面的调度办法。形如下

  /**     * 1、简略工作示例(Bean模式)     */    @XxlJob("demoJobHandler")    public ReturnT<String> demoJobHandler(String param) throws Exception {        XxlJobLogger.log("XXL-JOB, Hello World.");        System.out.println("======================param:"+param+"================================随机数:"+new Random().nextInt(1000));        return ReturnT.SUCCESS;    }

总结

如果选用计划一,也不是不行,就还得做一些革新,比方减少全局标记位,而且在设置标记位的时候,还要思考并发场景下,可能呈现的问题。因而还不如间接采纳计划二。计划的抉择肯定得要基于业务场景进行考量,不基于业务场景,谈技术计划,很容易采坑

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-xxl-job-executor