前言
上一节《1.snail-job初体验》中,已经运行了一个定时任务,初步了解snail-job的基本用法。本节,主要是针对集群定时任务,做进一步的了解。这里就包括任务管理页面中的每项配置作用,并对重要的配置项做代码测试。
本节目标
- 采用JDK17以上实现客户端
- 注解方式实现定时任务客户端
- 记录日志到任务服务端
- 任务管理页面中定时任务配置项详细解释
- 对阻塞策略、超时时间、最大重试次数配置项进行测试理解
Maven依赖
JDK17及其以上的maven依赖
xml 代码解读复制代码<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>3.3.3version>
dependency>
<dependency>
<groupId>com.aizudagroupId>
<artifactId>snail-job-client-starterartifactId>
<version>1.1.2version>
dependency>
<dependency>
<groupId>com.aizudagroupId>
<artifactId>snail-job-client-retry-coreartifactId>
<version>1.1.2version>
dependency>
<dependency>
<groupId>com.aizudagroupId>
<artifactId>snail-job-client-job-coreartifactId>
<version>1.1.2version>
dependency>
dependencies>
大概说明下snail-job依赖库的作用:
库名 | 主要作用 |
---|---|
snail-job-client-starter | snail-job客户端启动时,和springboot框架相结合的初始框架代码 |
snail-job-client-retry-core | 实现重试任务的核心代码。 |
snail-job-client-job-core | 实现定时任务的核心代码 |
说明:
如果你的项目中不涉及重试任务,实际上不引入
snail-job-client-retry-core
的依赖也是可以的,不会影响到定时任务;反之亦然。
logback配置文件
在本节目标中,希望把日志写到服务端上。所以这里需要配置下logback-spring.xml文件:
xml 代码解读复制代码"1.0" encoding="UTF-8"?>
<configuration>
<property name="log.path" value="./logs"/>
<property name="console.log.pattern"
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${console.log.pattern}pattern>
<charset>utf-8charset>
encoder>
appender>
<appender name="snailLogAppender" class="com.aizuda.snailjob.client.common.appender.SnailLogbackAppender">
appender>
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="file_info" />
<appender-ref ref="file_warn" />
<appender-ref ref="file_error" />
<appender-ref ref="snailLogAppender" />
root>
configuration>
测试类
由于在上一节中已经介绍过配置文件和启动类的注意事项了。这里补充说明一点,如果你的服务端ip和客户端ip不是同一台机器的话,建议在配置文件中指定一下客户端ip【snail-job.host=192.168.1.123
】,否则取到的默认ip可能不对,从而造成服务端访问不到客户端的情况。测试类具体注解测试类代码如下:
java 代码解读复制代码@Slf4j
@Component
@JobExecutor(name = "testSnailJobWithAnnotation")
public class TestSnailJobWithAnnotation {
public ExecuteResult jobExecute(JobArgs jobArgs) {
log.info("定时任务执行成功.参数值:{}", jobArgs);
SnailJobLog.LOCAL.info("LOCAL日志.参数值:{}", jobArgs);
SnailJobLog.REMOTE.info("REMOTE日志.参数值:{}", jobArgs);
return ExecuteResult.success("测试注解方式的定时任务成功");
}
}
说明:
- 默认执行的方法名是jobExecute,如果需要修改的话,则可以修改@JobExecutor的mothod属性。如:
@JobExecutor(name = "testSnailJobWithAnnotation", method="myJob")
执行器的名称在同一组下是不允许重复的。如果你另外一个定时任务类也叫
testSnailJobWithAnnotation
那么在客户端启动的时候就会报错:SnailJobClientException: 不允许executorName重复的
本测试代码中SnailJobLog.LOCAL.info和采用slf4j的log记录日志效果一样,都是在客户端记录日志;而SnailJobLog.REMOTE.info则是在服务端记录日志。
定时任务管理页面
对定时任务的任务管理和执行批次页面,进行了解。
任务管理-新增/编辑定时任务
下面是该在服务器的任务管理页面中,添加我们上面的测试类了。在这里顺便解释下定时任务的配置项。
任务名称
定时任务的一个名称,最好是看到这个名字,就知道这个定时是干嘛用的。
组名称
这个在上一节中已经有比较详细的描述。这里可以简单把组理解为项目或者应用。
状态
分为启用和禁用两种状态。禁用状态时,服务端不再调度该任务。并且只有禁用状态的任务才能被删除。
任务类型
本文主要是讲述集群任务类型的,这里先不展开其他的任务类型。目前仅需知道集群任务类型,能保证服务端可以按照下面将要说到的路由策略,只命中一台客户端节点执行任务。至于其他的任务类型,将在后续文章中单独介绍。
执行器类型
snail-job在支持java客户端的同时,还支持Python客户端。未来还可能支持GO语言的客户端。
执行器名称
最常用的是自定义执行器,由于我们客户端采用注解的方式,所以这里的名字和用注解中的name值一致即可。不用像上一篇那样要写全路径类名了。方法参数中填写的内容,可以通过方法参数的JobArgs对象获得。除了这个最最常用的自定义执行器,snail-job还内置了几个执行器名称:
执行器名称 | 作用 |
---|---|
Http执行器 | 通过http请求调用一个接口的方式,定时执行任务。 |
CMD执行器 | 定时执行window上的.bat文件 |
PowerShell执行器 | 定时执行PowerShell 脚本文件,通常是.ps1文件 |
Shell执行器 | 定时执行linux上的.sh文件 |
路由策略
就是服务端通过什么策略来路由到客户端。snail-job有如下路由策略:
路由策略 | 解释说明 |
---|---|
最后一个 | 客户端a、b、c三台集群的情况下,总是命中c这台机器 |
第一个 | 客户端a、b、c三台集群的情况下,总是命中a这台机器 |
轮询 | 客户端a、b、c三台集群的情况下,总是安装a、b、c这种每台命中一次的节奏周而复始 |
LRU | 客户端a、b、c三台集群的情况下,会命中最近最少使用的那台客户端。 |
随机 | 客户端a、b、c三台集群的情况下,随机命中一台 |
一致性哈希 | 客户端a、b、c三台集群的情况下,一致性哈希算法会稳定的调度其中一台机器。 |
阻塞策略
阻塞策略这个是处理服务端到了该触发客户端任务A的时候,但是发现任务A还在运行。此时就需要一个策略来处理该情况。
简单的说,就是服务端应该触发某个任务,发现该任务没结束呢,此时该咋办呢?那么由你来决定。你可以选择的处理方式有如下几种方式:
策略 | 解释 |
---|---|
丢弃 | 你都没干完,我不干 |
覆盖 | 你别干了,我来干 |
并行 | 直接开干 |
恢复 | 继续把失败的任务干完 |
这几个策略在本文后面的测试中,进行逐一测试验证
触发类型
服务端以哪种类型来触发客户端,包括如下可选类型:
类型名 | 说明 |
---|---|
固定时间 | 以一个固定时间间隔来触发客户端执行任务。 |
CRON表达式 | 以Cron表达式设置的时间来触发客户端执行任务 |
工作流 | 工作流这个会在后续文章单独介绍 |
时间间隔
会根据前面选择的触发类型不同而有所变化。
类型 | 时间间隔 |
---|---|
固定时间 | 这里是间隔的秒数。如:600秒,10分钟触发一次 |
CRON表达式 | 这里是一个cron表达式的触发。如:0 35 13 * * ? |
cron表达式管理页面有很好的支持,可以通过页面进行配置。尤其是其中还有验证表达式是否正确的最近5次运行时间
。
超时时间(秒)
这里的超时时间,就是你对这个定时任务预估完成的时间。如果设置的过短,可能导致其实客户端任务已经返回运行成功了,但是在任务批次列表【后面讲述】中显示任务执行超时
。
最大重试次数
首先说明,这里有几种情况会触发服务端重新调度客户端任务。
- 网络超时
- 客户端明确返回错误
- 客户端出现异常
这里设置的次数,就是发生上面情况时,重试的最大次数。
特别说明:
任务超时是不会触发服务端重新调度客户端任务的。
重试间隔(秒)
在需要重新调度客户端任务时,两次重试的时间间隔。
描述
对该任务的详细描述。
任务管理-任务列表
说明两个名词定义:
-
任务项
这个列表中的每一条记录叫任务项
-
批次
每个批次就是一次服务度对客户端的调度。而这个调度可能是一个或者多个任务。当然,针对本节讲述的集群定时任务来说,一个批次调度的是一个任务。而任务类型为:广播、 分片、 map、 mapreduce 的任务就会牵扯到多个任务。这个后续文章讲述。
任务管理-执行批次
执行批次
页面可以通过两种方式进入:
- 在任务管理-任务列表中,点击任务项后面操作中的
批次
按钮 - 直接在菜单项中点击
执行批次
菜单项
两者的区别是,任务列表中点击某个任务项后面的批次
按钮,则直接看到的该任务下的批次列表;而直接通过菜单项看到的是所有任务的批次列表。
进行测试
这里测试的目的包括:
- 为了实现本节目标,验证日志记录到服务器上。
- 为了深入理解阻塞策略、超时时间、最大重试次数配置项对定时任务的影响
验证注解方式定时任务
把我们最开始写的测试类,进行验证。
客户端代码
java 代码解读复制代码@Slf4j
@Component
@JobExecutor(name = "testSnailJobWithAnnotation")
public class TestSnailJobWithAnnotation {
public ExecuteResult jobExecute(JobArgs jobArgs) {
log.info("定时任务执行成功.参数值:{}", jobArgs);
SnailJobLog.LOCAL.info("LOCAL日志.参数值:{}", jobArgs);
SnailJobLog.REMOTE.info("REMOTE日志.参数值:{}", jobArgs);
return ExecuteResult.success("测试注解方式的定时任务成功");
}
}
页面配置
配置项 | 配置内容 |
---|---|
任务名称 | 注解定时任务 |
组名称 | service_plat |
状态 | 启用 |
任务类型 | 集群 |
执行器类型 | java |
执行器名称 | testSnailJobWithAnnotation |
方法参数 | {"date":"2024-09-20"} |
路由策略 | 轮询 |
阻塞策略 | 丢弃 |
触发类型 | 固定时间 |
间隔时长 | 60秒 |
超时时间(秒) | 60秒 |
最大重试次数 | 3 |
重试间隔 | 1秒 |
测试结果
-
执行批次页面中任务处理成功
-
日志中能看到记录到服务端的日志
点击上图中某个批次后面的日志,可以看到日志的详情信息
点击
查看日志
后
测试总结
- 注解方式的任务通过@JobExecutor来实现
- SnailJobLog.LOCAL.info和log.info作用基本等价,都是在客户端写日志信息
- SnailJobLog.REMOTE.info可以把日志写到服务端
验证最大重试次数和间隔
在前面介绍管理页面的时候,已经介绍过什么情况下会重试,在这里再次回顾下:
- 网络超时
- 客户端明确返回错误
- 客户端出现异常
那我们客户端代码随便来个被0除的异常即可。余下的两种情况可自行进行测试。
客户端代码
java 代码解读复制代码@Component
public class TestRetryTimes extends AbstractJobExecutor {
@Override
protected ExecuteResult doJobExecute(JobArgs jobArgs) {
int i = 1/0;
return ExecuteResult.success();
}
}
这里还是用上一篇文章中推荐的继承虚基类方式来做定时任务。好处有:
- idea能自动补充需要实现的接口类。省得记入参和返回参数。
- 避免任务重名
页面关键配置
其他配置项和上面的验证注解方式定时任务
配置一样
配置项 | 配置内容 |
---|---|
任务名称 | 测试最大重试次数和间隔 |
执行器名称 | com.bjltd.test.TestRetryTimes |
触发类型 | CRON表达式 |
间隔时长 | 0 22 09 * * ? |
最大重试次数 | 4 |
重试间隔 | 10秒 |
说明
- 执行器名称要填写包全路径名。这个是和注解方式有很大区别。
- 这里采用cron表达式,任务每天就激活一次。主要为了方便查看测试结果,也更贴合实际应用场景。
测试结果
-
客户端的控台
这里抽取关键打印信息:
shell代码解读复制代码2024-09-23 09:22:10 [snail-netty-server-2] INFO c.a.s.c.job.core.client.JobEndPoint - 任务执行/调度失败执行重试. 重试次数:[1] 2024-09-23 09:22:20 [snail-netty-server-3] INFO c.a.s.c.job.core.client.JobEndPoint - 任务执行/调度失败执行重试. 重试次数:[2] 2024-09-23 09:22:31 [snail-netty-server-4] INFO c.a.s.c.job.core.client.JobEndPoint - 任务执行/调度失败执行重试. 重试次数:[3] 2024-09-23 09:22:41 [snail-netty-server-5] INFO c.a.s.c.job.core.client.JobEndPoint - 任务执行/调度失败执行重试. 重试次数:[4]
-
任务管理页面查看日志
任务管理页面->点任务名称为
测试最大重试次数和间隔
任务项后面的批次
按钮。在执行批次列表中点批次后面的日志
按钮。在执行批次详情页面中点击
查看日志
按钮在日志详情中可以看到本批次的详细情况
测试总结
-
网络超时、客户端明确返回错误、客户端出现异常会触发重试
-
最大重试次数可以设置重试多少次
-
重试间隔可以设置每次重试之间间隔的时间
验证阻塞策略-丢弃
策略 | 解释 |
---|---|
丢弃 | 你都没干完,我不干 |
触发阻塞的前提是:服务端应该触发某个任务,发现该任务没结束。结合前提,这里大体测试思路是:每分钟执行一次定时任务,而任务执行时间是5分钟。这样就会触发阻塞策略了。
客户端代码
java 代码解读复制代码@Component
public class TestDiscardJob extends AbstractJobExecutor {
@Override
protected ExecuteResult doJobExecute(JobArgs jobArgs) {
// 休眠5分钟
ThreadUtil.sleep(5, TimeUnit.MINUTES);
return ExecuteResult.success();
}
}
页面配置
配置项 | 配置内容 |
---|---|
任务名称 | 测试阻塞策略-丢弃 |
执行器名称 | com.bjltd.test.TestDiscardJob |
阻塞策略 | 丢弃 |
触发类型 | 固定时间 |
间隔时长 | 60秒 |
超时时间 | 600秒 |
测试结果
1527这个批次,状态会从
运行中
变为处理成功
。执行时长也从空更新为最终的执行时长了。
测试总结
- 丢弃策略会一直等待前一个任务做完后,才会创建新的批次去调用客户端运行任务
- 在某种程度上解决了幂等性,但不是绝对的
验证阻塞策略-覆盖
策略 | 解释 |
---|---|
覆盖 | 你别干了,我来干 |
新批次开始之前会尝试中断旧批次的线程,但是不一定能终止掉。这里可以理解成在新批次开始前,调用了一个旧批次任务线程池的shutDownNow方法
客户端代码
-
无法中断的情况
java代码解读复制代码@Slf4j @Component public class TestOverlayCanNotInterrupted extends AbstractJobExecutor { @Override protected ExecuteResult doJobExecute(JobArgs jobArgs) { log.info("{}开始执行任务", Thread.currentThread().getName()); for(int i = 1; i <= 5; i++) { log.info("{}执行第{}次", Thread.currentThread().getName(), i); ThreadUtil.sleep(60, TimeUnit.SECONDS); } log.info("{}任务执行完成", Thread.currentThread().getName()); return ExecuteResult.success(); } }
-
可以中断的情况
java代码解读复制代码@Slf4j @Component public class TestOverlayCanInterrupted extends AbstractJobExecutor { @Override protected ExecuteResult doJobExecute(JobArgs jobArgs) { log.info("{}开始执行任务", Thread.currentThread().getName()); int i = 1; while (!Thread.currentThread().isInterrupted()) { log.info("{}执行第{}次", Thread.currentThread().getName(), i); try { Thread.sleep(60000); }catch (InterruptedException e) { log.info("{}任务被中断", Thread.currentThread().getName()); Thread.currentThread().interrupt();; } i++; } log.info("{}任务执行完成", Thread.currentThread().getName()); return ExecuteResult.success(); } }
页面配置
-
无法中断的配置
配置项 配置内容 任务名称 测试阻塞策略-覆盖-无法中断 执行器名称 com.bjltd.test.TestOverlayCanNotInterrupted 阻塞策略 覆盖 触发类型 固定时间 间隔时长 60秒 超时时间 600秒 -
可以中断的配置
配置项 配置内容 任务名称 测试阻塞策略-覆盖-可中断 执行器名称 com.bjltd.test.TestOverlayCanInterrupted 阻塞策略 覆盖 触发类型 固定时间 间隔时长 60秒 超时时间 600秒
测试结果
-
无法中断的测试结果
客户端日志信息:
shell代码解读复制代码2024-09-24 11:19:51 [snail-netty-server-1] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1716] 任务调度成功. 2024-09-24 11:19:51 [snail-job-job-1,716-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,716-1开始执行任务 2024-09-24 11:19:51 [snail-job-job-1,716-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,716-1执行第1次 2024-09-24 11:20:01 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[6] 2024-09-24 11:20:43 [snail-job-job-1,716-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,716-1执行第2次 2024-09-24 11:20:43 [snail-job-job-1,716-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,716-1执行第3次 2024-09-24 11:20:50 [snail-netty-server-3] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1717] 任务调度成功. 2024-09-24 11:20:50 [snail-job-job-1,717-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,717-1开始执行任务 2024-09-24 11:20:50 [snail-job-job-1,717-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,717-1执行第1次 2024-09-24 11:21:01 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[14] 2024-09-24 11:21:43 [snail-job-job-1,717-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,717-1执行第2次 2024-09-24 11:21:43 [snail-job-job-1,717-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,717-1执行第3次 2024-09-24 11:21:43 [snail-job-job-1,716-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,716-1执行第4次 2024-09-24 11:21:50 [snail-netty-server-5] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1718] 任务调度成功. 2024-09-24 11:21:50 [snail-job-job-1,718-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,718-1开始执行任务 2024-09-24 11:21:50 [snail-job-job-1,718-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,718-1执行第1次 2024-09-24 11:22:01 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[22] 2024-09-24 11:22:43 [snail-job-job-1,717-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,717-1执行第4次 2024-09-24 11:22:43 [snail-job-job-1,716-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,716-1执行第5次 2024-09-24 11:22:43 [snail-job-job-1,718-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,718-1执行第2次 2024-09-24 11:22:43 [snail-job-job-1,718-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,718-1执行第3次 2024-09-24 11:22:50 [snail-netty-server-7] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1719] 任务调度成功. 2024-09-24 11:22:50 [snail-job-job-1,719-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,719-1开始执行任务 2024-09-24 11:22:50 [snail-job-job-1,719-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,719-1执行第1次 2024-09-24 11:23:01 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[30] 2024-09-24 11:23:43 [snail-job-job-1,719-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,719-1执行第2次 2024-09-24 11:23:43 [snail-job-job-1,719-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,719-1执行第3次 2024-09-24 11:23:43 [snail-job-job-1,717-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,717-1执行第5次 2024-09-24 11:23:43 [snail-job-job-1,716-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,716-1任务执行完成 2024-09-24 11:23:43 [snail-job-job-1,718-1] INFO c.b.t.TestOverlayCanNotInterrupted - snail-job-job-1,718-1执行第4次 2024-09-24 11:23:50 [snail-netty-server-9] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1720] 任务调度成功.
从日志打印可以看出,1716这个批次并没有被真正中断,还是会在后台持续的工作。
任务批次列表中的显示
-
可以中断的测试结果
客户端日志信息:
shell代码解读复制代码2024-09-24 15:04:41 [snail-netty-server-1] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1935] 任务调度成功. 2024-09-24 15:04:41 [snail-job-job-1,935-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,935-1开始执行任务 2024-09-24 15:04:41 [snail-job-job-1,935-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,935-1执行第1次 2024-09-24 15:04:51 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[4] 2024-09-24 15:05:40 [snail-job-job-1,935-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,935-1任务被中断 2024-09-24 15:05:40 [snail-job-job-1,935-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,935-1任务执行完成 2024-09-24 15:05:41 [snail-netty-server-3] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1936] 任务调度成功. 2024-09-24 15:05:41 [snail-job-job-1,936-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,936-1开始执行任务 2024-09-24 15:05:41 [snail-job-job-1,936-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,936-1执行第1次 2024-09-24 15:05:52 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[12] 2024-09-24 15:06:40 [snail-job-job-1,936-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,936-1任务被中断 2024-09-24 15:06:40 [snail-job-job-1,936-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,936-1任务执行完成 2024-09-24 15:06:40 [snail-netty-server-5] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1937] 任务调度成功. 2024-09-24 15:06:40 [snail-job-job-1,937-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,937-1开始执行任务 2024-09-24 15:06:40 [snail-job-job-1,937-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,937-1执行第1次 2024-09-24 15:06:51 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[20] 2024-09-24 15:07:40 [snail-job-job-1,937-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,937-1任务被中断 2024-09-24 15:07:40 [snail-job-job-1,937-1] INFO c.b.test.TestOverlayCanInterrupted - snail-job-job-1,937-1任务执行完成
从日志输出能看出来,每个批次的任务都会被后面的新批次任务给停止。
任务批次列表中的显示
测试总结
- 新批次任务会停止上个批次任务,但是不保证一定停止成功。
- 如果想让任务拥有被中断的能力,那么需要在写任务代码时,自己处理。比如本例通用循环判断当前线程是不是被中断。如果你的任务本身不具备这种能力。基本相当于下面将要验证的并行效果一样了。
验证阻塞策略-并行
策略 | 解释 |
---|---|
并行 | 直接开干 |
这个策略顾名思义,就是和上一个批次的任务可以同时执行。
客户端代码
java 代码解读复制代码@Slf4j
@Component
public class TestConcurrency extends AbstractJobExecutor {
@Override
protected ExecuteResult doJobExecute(JobArgs jobArgs) {
log.info("{}开始执行任务", Thread.currentThread().getName());
for(int i = 1; i <= 5; i++) {
log.info("{}执行第{}次", Thread.currentThread().getName(), i);
ThreadUtil.sleep(60, TimeUnit.SECONDS);
}
log.info("{}任务执行完成", Thread.currentThread().getName());
return ExecuteResult.success();
}
}
页面配置
配置项 | 配置内容 |
---|---|
任务名称 | 测试阻塞策略-覆盖-可中断 |
执行器名称 | com.bjltd.test.TestConcurrency |
阻塞策略 | 并行 |
触发类型 | 固定时间 |
间隔时长 | 60秒 |
超时时间 | 600秒 |
测试结果
测试总结
- 这个在实际应用中,一定要谨慎使用。
- 采用该策略一定要充分考虑幂等性问题。
验证阻塞策略-恢复
策略 | 解释 |
---|---|
恢复 | 继续把失败的任务干完 |
该模式是用在任务类型是多个任务的情况下使用的,比如像Map这种很多任务的情景下,还有就是工作流。作用就是跑其中失败的任务。集群任务就一个任务项,执行完后批次状态就变了,连触发任务都不能了,所以千万别在集群模式下选该策略。这个恢复策略,在后续讲解中再进行介绍。
验证超时时间
超时时间的设置,目的是在定时任务到了这个阈值还没有执行完,那么就会调用批次任务线程池的shutDownNow方法。这个和上面说到的覆盖策略很相似。同样也都不能保证任务一定被停止。
客户端代码
java 代码解读复制代码@Slf4j
@Component
public class TestTimeout extends AbstractJobExecutor {
@Override
protected ExecuteResult doJobExecute(JobArgs jobArgs) {
try {
// 休眠3分钟
Thread.sleep(3*60*1000);
}catch (InterruptedException e){
return ExecuteResult.failure();
}
return ExecuteResult.success();
}
}
页面配置
配置项 | 配置内容 |
---|---|
任务名称 | 测试超时时间 |
执行器名称 | com.bjltd.test.TestTimeout |
路由策略 | 轮询 |
阻塞策略 | 丢弃 |
触发类型 | 固定时间 |
间隔时长 | 60秒 |
超时时间 | 30秒 |
测试结果
客户端日志信息:
shell代码解读复制代码2024-09-24 16:53:40 [snail-netty-server-1] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1992] 任务调度成功. 2024-09-24 16:53:40 [snail-job-job-1,992-1] INFO com.bjltd.test.TestTimeout - snail-job-job-1,992-1开始执行任务 2024-09-24 16:53:50 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[7] 2024-09-24 16:54:10 [snail-job-job-1,992-1] INFO com.bjltd.test.TestTimeout - snail-job-job-1,992-1任务被中断 2024-09-24 16:54:40 [snail-netty-server-3] INFO c.a.s.c.job.core.client.JobEndPoint - 批次:[1993] 任务调度成功. 2024-09-24 16:54:40 [snail-job-job-1,993-1] INFO com.bjltd.test.TestTimeout - snail-job-job-1,993-1开始执行任务 2024-09-24 16:54:50 [nioEventLoopGroup-2-1] INFO c.a.s.c.c.l.report.ReportLogListener - Data report log successfully requestId:[15] 2024-09-24 16:55:10 [snail-job-job-1,993-1] INFO com.bjltd.test.TestTimeout - snail-job-job-1,993-1任务被中断
从客户端日志中可以看出来,任务从开始到任务被中断间隔30秒。
任务批次列表中显示
测试总结
- 超时时间是设置任务最大可以执行时长。到了这个时间就会停止任务。
- 停止任务并不保证必然停止
- 它是一个保底方案。避免因为各种意外而造成的长时间任务驻留。
总结
-
会用注解和继承类两种方式,实现自己的客户端定时任务。
-
通过在logback配置中加SnailLogbackAppender,能把日志写到服务端。
-
阻塞策略是反正在该执行任务的时候,还有任务还在执行。可以选择的策略如下:
策略 解释 丢弃 你都没干完,我不干 覆盖 你别干了,我来干 并行 直接开干 恢复 继续把失败的任务干完 -
超时时间是到了这个时间点,如果任务还没执行完,就调用该任务线程池的shutdownNow方法。
评论记录:
回复评论: