xxl-job是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展、开箱即用。我部门大部分定时任务调度都是基于xxl-job,诸如报表统计、定时数据同步等。
今天的素材来源于某天产品经理想在定时同步报表数据的基础上,再增长一个手动触发报表数据同步的功能。即在报表页面上新增一个手动同步的按钮,触发该按钮就能够执行报表数据同步java
一、保留定时同步功能,同时新增手动同步二、手动同步的数据产生的效果要和定时数据同步的产生效果同样git
一、方案1、新建一个手动调用的controller,controller触发数据同步逻辑service
其实就是把写在xxl-job执行器里面的同步逻辑,再放到controller执行一遍github
二、方案2、新建一个手动调用的controller,在controller里面直接触发xxl-job执行器
在原先的定时器场景,咱们为了不定时器里面的同步逻辑还没完成,下次定时器就触发致使数据同步不许确,咱们在执行器里面作一些手段进行规避,好比设置同步完成标志位等。
若是基于方案一,方案看似可行,其实存在潜在的坑点。即定时器执行的时候,手动恰好触发执行,或者反过来,手动触发的时候,定时器也执行了。这样就会致使数据同步执行屡次,致使数据不许确。spring
后面咱们调研了xxl-job,看到了xxl-job有提供restful风格触发执行器的功能,这个功能简直就是为咱们量身定作,当手动调用的时候,触发执行器,由于执行的是执行器里面的调用逻辑,所以就会触发咱们为避免数据同步不许确所采起的手段springboot
其具体介绍能够查看官网,其连接以下restful
https://www.xuxueli.com/xxl-job/#6.2 执行器 RESTful API并发
本例的核心代码块app
@RestController @RequestMapping(value = "xxl-job") @Api(tags = "xxl-job restful调度") @Profile("job") @Slf4j public 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,就是执行器里面的调度方法。形以下dom
/** * 一、简单任务示例(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; }
若是选用方案一,也不是不行,就还得作一些改造,好比增长全局标志位,并且在设置标志位的时候,还要考虑并发场景下,可能出现的问题。所以还不如直接采用方案二。方案的选择必定得要基于业务场景进行考量,不基于业务场景,谈技术方案,很容易采坑分布式
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-xxl-job-executor