XXL-JOB逻辑自测及执行参数配置踩坑

Posted johnny233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XXL-JOB逻辑自测及执行参数配置踩坑相关的知识,希望对你有一定的参考价值。

概述

关于XXL-JOB的使用遇到的问题记录。对XXL-JOB不熟的,可以先参考分布式任务调度平台XXL-JOB深度实战

实战

业务DTO定义如下:

@Data
public class AdAccountDTO 
	private String accountId;
	/**
     * yyyy-MM-dd HH:mm:ss
     */
	private String startCreateTime;
    private String endCreateTime;

JobHandler定义如下:

@Slf4j
@Service
@JobHander(value = "accountDependBindJobHandler")
public class AccountDependBindJobHandler extends IJobHandler 

    @Resource
    private BaseService<AdAccountDTO, Void> accountDependBindService;

    @Override
    public ReturnT<String> execute(String... params) 
        try 
            log.info("accountDependBindJobHandler begin");
            AdAccountDTO account = new AdAccountDTO();
            account.setCreatorName("system");
            // 32行
            if (params.length > 0) 
                account.setStartCreateTime(params[0]);
            
            if (params.length > 1) 
                // 广告主
                account.setAccountId(params[1]);
            
            if (params.length > 2) 
                account.setEndCreateTime(params[2]);
            
            log.info("accountDependBindJobHandler account: ", JSONObject.toJSONString(account));
            accountDependBindService.execute(account);
            log.info("accountDependBindJobHandler end");
         catch (Exception e) 
            log.error("accountDependBindJobHandler fail", e);
            return ReturnT.FAIL;
        
        return ReturnT.SUCCESS;
    

业务实现类AccountDependBindService,此处仅展示部分:

@Override
protected void business(BizContextVo<AdAccountDTO, Void> bizContextVo) 
    AdAccountDTO accountDTO = bizContextVo.getIn();
    String startDate = accountDTO.getStartCreateTime();
    String endDate = accountDTO.getEndCreateTime();
    boolean check = StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate) &&
            !DateUtils.isBefore(accountDTO.getStartCreateTime(), accountDTO.getEndCreateTime());
    if (check) 
        throw new BaseException("", "时间不匹配");
    
    // 可以兼容startDate为null,"",及" "等情况
    check = StringUtils.isBlank(startDate);
    if (check) 
        // 默认跑数1天
        accountDTO.setStartCreateTime(DateUtils.formatDate(DateUtils.addDays(new Date(), -1), DateUtils.DATE_FORMAT_YMDHMS));
    
    check = StringUtils.isBlank(endDate);
    if (check) 
        accountDTO.setEndCreateTime(DateUtils.getCurrentTime());
    
    log.info("accountDependBindService account: ", JSONObject.toJSONString(accountDTO));
    // 根据条件查询
    List<AdAccountDTO> accountList = advertiserMapper.selectAllNewAdvertiser(accountDTO);	

XXL-JOB任务配置如下:

想要实现的效果是,如果执行参数为空,则取当前时间-24小时的数据开始同步。如果参数不为空,支持1-3个参数,第一个参数是同步开始时间,第二个是同步的账户,第三个是同步结束时间。

问题

自测

因为代码的改动都是在本地,即开发环境。本地无法直接连接到测试环境的xxl-job系统,即在测试环境的xxl-job管理界面手动执行任务时,并不能把任务下发到我的localhost:8080调试环境,不能断点调试。也许xxl-job有这个功能,但是我并不知道。 参考下面的【本地调试】章节实现方案。

想要验证job代码的逻辑,有以下3种方式:

  1. 代码提交到Git,fat环境打包部署,手动执行Job,查看日志,查看数据表,验证功能逻辑;
  2. 写一个Controller,Controller和JobHandler都是调用同一个Service业务实现类;
  3. 写一个UT,测试JobHandler的逻辑,同时还可以验证执行参数。

方式1,效率最低,得反复修改代码,反复提交,反复部署;
方式2,如果前端用不到Controller里新增的接口,或者后端开发人员也不需要借助于接口来补数据,或者同步数据,则会造成无用代码冗余;

所以我们选择方式3。在\\src\\test\\java目录下面新增一个UT测试类:

@RunWith(SpringRunner.class)
// 指定应用启动类
@SpringBootTest(classes = WebApplication.class)
public class JobHandlerTest 
    @Resource
    private AccountDependBindJobHandler accountDependBindJobHandler;

    @Test
    public void testAuto() 
    	// 模拟参数为空,null的情况
        // accountDependBindJobHandler.execute(null);
        // 模拟参数为空,empty的情况
        // String[] params = new String[];
        // 模拟2个参数的情况
        String[] params = new String[]"2022-09-26", "34343434";
        accountDependBindJobHandler.execute(params);
    

本地调试

XXL-JOB的执行器管理页如下:

注册方式可以是自动注册,也可以是手动注册。我们应用由于其特殊性,只能使用手动注册。参考分布式任务调度平台XXL-JOB深度实战执行器章节。

我们不可能在本地搭建一套XXL-JOB管理平台,即:http://dev-xxljob.johnny.com/jobgroup。公司搭建有fat环境的一套平台:http://fat-xxljob.johnny.com/jobgroup。能不能通过fat-xxl-job来调度执行我们本地的代码,当然可以!

编辑执行器,修改机器地址,指向我的本机IP:

然后在页面点击执行任务,任务详情如下:

然后请求确实打到本地,停在断点处:

这个截图也说明,如果执行参数为空时,params参数是null,而不是空字符串。

注意:不能启动web应用!!!

参考上面的文章,那篇文章提到,这里再说明下:web应用模块用于把任务注册同步到XXL-JOB平台,里面没有这个JobHandler类;dataset才是JobHandler所在的应用模块,这也是为什么不能使用自动注册方式。

事实上,如果同时启动web和dataset两个应用模块。在XXL-JOB页面点击执行任务,会概率性出现调度失败的报错:

点击查看调度备注:

报错:找不到JobHandler。

执行参数配置

参考上面的UT类,模拟5种情况:

  1. 参数为null
  2. 参数为空字符串
  3. 1个参数
  4. 2个参数,多个参数直接使用英文逗号分隔
  5. 3个参数

情况1自测下来会有报错:

ERROR c.p.c.p.s.AccountDependBindJobHandler - accountDependBindJobHandler fail
java.lang.NullPointerException: null
	at com.johnny.cbd.platform.scheduled.AccountDependBindJobHandler.execute$original$Iu6X8Nnv(AccountDependBindJobHandler.java:32)
	at com.johnny.cbd.platform.scheduled.AccountDependBindJobHandler.execute$original$Iu6X8Nnv$accessor$aikoAyrI(AccountDependBindJobHandler.java)
	at com.johnny.cbd.platform.scheduled.AccountDependBindJobHandler$auxiliary$HcNstxGt.call(Unknown Source)
	at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86)
	at com.johnny.cbd.platform.scheduled.AccountDependBindJobHandler.execute(AccountDependBindJobHandler.java)
	at com.johnny.job.core.thread.JobThread.run(JobThread.java:141)

代码优化如下:

if (params != null && params.length > 0) 
    account.setStartCreateTime(params[0]);

if (params != null && params.length > 1) 
    account.setAccountId(params[1]);

if (params != null && params.length > 2) 
    account.setEndCreateTime(params[2]);

XXL-JOB页面参数配置如果为空,就是上面的情况1,参考上面章节截图。

XXL-JOB页面参数能实现参数配置为空字符串吗?答案是:不能!!


当然改成双引号也不行!!!

改成双引号后,应用打印的日志:

INFO c.p.c.p.s.AccountDependBindJobHandler - accountDependBindJobHandler account: "creatorName":"system","needPage":true,"offset":10,"pageSize":10,"start":0,"startCreateTime":"\\"\\""

默认以当前时间为截至时间:

INFO c.p.c.p.s.a.AccountDependBindServiceImpl - accountDependBindService account: "creatorName":"system","endCreateTime":"2022-09-26 13:00:20","needPage":true,"offset":10,"pageIndex":1,"pageSize":10,"start":0,"startCreateTime":"\\"\\"" 

前面没有提到mapper.xml方法:

<select id="selectAllNewAdvertiser" resultType="com.johnny.dto.AdAccountDTO">
    SELECT advertiser_id accountId, 4 as type FROM channel_advertiser_id WHERE isactive = 1
    <if test="status != null">
        and status = #status
    </if>
    <if test="accountId != null">
        AND advertiser_id = #accountId
    </if>
    <if test="startCreateTime != null">
        AND insert_time &gt;= #startCreateTime
    </if>
    <if test="endCreateTime != null">
        AND insert_time &lt;= #endCreateTime
    </if>
</select>

满足if条件:startCreateTime != null,拼接得到的SQL为:

SELECT advertiser_id accountId, 4 as type FROM channel_advertiser_id WHERE isactive = 1 and advertiser_id = '1740858985811982' and insert_time >= '""'

有日志为证:

2022-09-26 16:42:53,603 [main] DEBUG c.p.c.b.d.C.selectAllNewAdvertiser- ==>  Preparing: SELECT advertiser_id accountId, 4 as type FROM channel_advertiser_id WHERE isactive = 1 and status = ? AND advertiser_id = ? AND insert_time >= ? AND insert_time <= ? 
2022-09-26 16:42:53,827 [main] DEBUG c.p.c.b.d.C.selectAllNewAdvertiser- ==> Parameters: 1(Integer), 1740858985811982(String), ""(String), 2022-09-26 16:42:49(String)
2022-09-26 16:42:53,977 [main] DEBUG c.p.c.b.d.C.selectAllNewAdvertiser- <==      Total: 8

截图为证:

也就是说,我们在DataGrip上面看到虽然有Incorrect datetime value问题,但是mysql会做隐式转换,还是可以查询出结果来。

注,MySQL版本:5.7.29-32-log。

另外3种参数配置case,没啥好说的。

任务调度平台XXL-JOB使用

参考技术A

分布式任务调度平台xxl-job是一个开源框架。

2.1 application.yml的配置文件
yml配置文件加上配置。

其中的”@xxl.job.executor.appname@”等配置是在config_ local.properties 文件里,参数具体意思参考文档。通常yml里是写具体的参数值,这里用这种方式是如何实现和config_ local.properties 文件对应的,是通过maven的prefile配置吗?暂时不懂,还需去了解。

编写XxlJobConfig类

写一个任务类,继承IJobHandler。这个类需要在上面的XxlJobConfig里配置的包下?

2.2 application.properties的配置文件
application.properties配置文件加上配置。

然后编写XxlJobConfig类、写一个任务类,继承IJobHandler,同上。到这里就把springboot的配置讲完了。源码里还有和spring整合的demo,也很简单,可以参考。

任务管理添加任务

到此,整合xxl-job就完成了,非常方便实用。
欢迎工作一到五年的Java工程师朋友们加入Java高并发QQ群:219571750,群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

以上是关于XXL-JOB逻辑自测及执行参数配置踩坑的主要内容,如果未能解决你的问题,请参考以下文章

docker部署xxl-job 通用反射执行器

XXL-JOB分布式任务调度框架-策略详解

xxl-job+rabbitmq 进行定时的微信消息推送

任务调度平台XXL-JOB使用

一文带你使用xxl-job定时任务

Mac下 node安装、配置及踩坑