简单任务
@Component
public class SimpleJobHandler {
@XxlJob(value ="simpleJobHandler" )
public ReturnT<String> execute(String param) throws InterruptedException {
IntStream.rangeClosed(1,20).forEach(index->{
XxlJobLogger.log("simpleJobHandler>>"+index);
});
//官方文档说 如果任务超时 是采用interrupt机制打断子线程的,因此需要将InterruptedException 向上抛出
//不能catch,否则任务超时后 任务还会被正常执行完
Thread.sleep(ThreadLocalRandom.current().nextInt(10000));
//任务超时后 这句日志不会被打印出来
XxlJobLogger.log("执行完毕");
return ReturnT.SUCCESS;
}
}
注意:xxl-job任务需用XxlJobLogger输出日志
其中页面上JobHandler对应于代码上@XxlJob的value值,超时时间设置2s
由于本地测试时 运行了多个执行器,所以路由策略那里选用了
轮询
。也可根据实际情况自行调整
查看下运行日志
发现当任务执行超时后,程序即被中断,后续的代码逻辑不再被执行。
分片任务
使用分片是为了更大效率地利用执行器集群资源,比如有一个任务需要处理20W条数据,每条数据的业务逻辑处理要0.1s。对于普通任务来说,只有一个线程来处理 可能需要5~6个小时才能处理完。
如果将20W数据均匀分给集群里的3台机器同时处理,那么耗时会大大缩短,也能充分利用集群资源。
在xxl-job里,如果有一个执行器集群有3个机器,那么分片总数是3,分片序号0,1,2 分别对应那三台机器。
举例:
有一个执行器集群,有三台机器。对一批用户信息进行处理,处理规则如下
- id % 分片总数 余数是0 的,在第1个执行器上执行
- id % 分片总数 余数是1 的,在第2个执行器上执行
- id % 分片总数 余数是2 的,在第3个执行器上执行
@Component
public class ShardingJob {
private List<User> userList;
@PostConstruct
public void init() {
userList = LongStream.rangeClosed(1, 10)
.mapToObj(index -> new User(index, "wojiushiwo" + index))
.collect(Collectors.toList());
}
@XxlJob(value = "shardingJobHandler")
public ReturnT<String> execute(String param) {
//获取分片参数
ShardingUtil.ShardingVO shardingVo = ShardingUtil.getShardingVo();
XxlJobLogger.log("分片参数,当前分片序号={},总分片数={}", shardingVo.getIndex(), shardingVo.getTotal());
for (int i = 0; i < userList.size(); i++) {
//将数据均匀地分布到各分片上执行
if (i % shardingVo.getTotal() == shardingVo.getIndex()) {
XxlJobLogger.log("第 {} 片, 命中分片开始处理{}", shardingVo.getIndex(), userList.get(i).toString());
} else {
XxlJobLogger.log("{},忽略", shardingVo.getIndex());
}
}
return ReturnT.SUCCESS;
}
}
如果是数据库数据的话,可以进行如下处理,让每个分片执行一部分数据
-- 其中count是分片总数,index是当前分片数
select id,name
from user
where status=1 and mod(id,#{count})=#{index};
下面查看下三个执行器的执行日志: