SpringBoot定時任務 - 開箱即用分散式任務框架xxl-job
除了前文介紹的ElasticJob,xxl-job在很多中小公司有著應用(雖然其程式碼和設計等質量並不太高,License不夠開放,有著個人主義色彩,但是其具體開箱使用的便捷性和功能相對完善性,這是中小團隊採用的主要原因);XXL-JOB是一個分散式任務排程平臺,其核心設計目標是開發迅速、學習簡單、輕量級、易擴充套件。本文介紹XXL-JOB以及SpringBoot的整合。@pdai
知識準備
需要對分散式任務的知識體系和xxl-Job有基本的理解。@pdai
什麼是xxl-job
XXL-JOB是一個分散式任務排程平臺,其核心設計目標是開發迅速、學習簡單、輕量級、易擴充套件。現已開放原始碼並接入多家公司線上產品線,開箱即用。如下內容來源於xxl-job官網
支援如下特性:
- 1、簡單:支援通過Web頁面對任務進行CRUD操作,操作簡單,一分鐘上手;
- 2、動態:支援動態修改任務狀態、啟動/停止任務,以及終止執行中任務,即時生效;
- 3、排程中心HA(中心式):排程採用中心式設計,“排程中心”自研排程元件並支援叢集部署,可保證排程中心HA;
- 4、執行器HA(分散式):任務分散式執行,任務"執行器"支援叢集部署,可保證任務執行HA;
- 5、註冊中心: 執行器會週期性自動註冊任務, 排程中心將會自動發現註冊的任務並觸發執行。同時,也支援手動錄入執行器地址;
- 6、彈性擴容縮容:一旦有新執行器機器上線或者下線,下次排程時將會重新分配任務;
- 7、觸發策略:提供豐富的任務觸發策略,包括:Cron觸發、固定間隔觸發、固定延時觸發、API(事件)觸發、人工觸發、父子任務觸發;
- 8、排程過期策略:排程中心錯過排程時間的補償處理策略,包括:忽略、立即補償觸發一次等;
- 9、阻塞處理策略:排程過於密集執行器來不及處理時的處理策略,策略包括:單機序列(預設)、丟棄後續排程、覆蓋之前排程;
- 10、任務超時控制:支援自定義任務超時時間,任務執行超時將會主動中斷任務;
- 11、任務失敗重試:支援自定義任務失敗重試次數,當任務失敗時將會按照預設的失敗重試次數主動進行重試;其中分片任務支援分片粒度的失敗重試;
- 12、任務失敗告警;預設提供郵件方式失敗告警,同時預留擴充套件介面,可方便的擴充套件簡訊、釘釘等告警方式;
- 13、路由策略:執行器叢集部署時提供豐富的路由策略,包括:第一個、最後一個、輪詢、隨機、一致性HASH、最不經常使用、最近最久未使用、故障轉移、忙碌轉移等;
- 14、分片廣播任務:執行器叢集部署時,任務路由策略選擇"分片廣播"情況下,一次任務排程將會廣播觸發叢集中所有執行器執行一次任務,可根據分片引數開發分片任務;
- 15、動態分片:分片廣播任務以執行器為維度進行分片,支援動態擴容執行器叢集從而動態增加分片數量,協同進行業務處理;在進行大資料量業務操作時可顯著提升任務處理能力和速度。
- 16、故障轉移:任務路由策略選擇"故障轉移"情況下,如果執行器叢集中某一臺機器故障,將會自動Failover切換到一臺正常的執行器傳送排程請求。
- 17、任務進度監控:支援實時監控任務進度;
- 18、Rolling實時日誌:支援線上檢視排程結果,並且支援以Rolling方式實時檢視執行器輸出的完整的執行日誌;
- 19、GLUE:提供Web IDE,支援線上開發任務邏輯程式碼,動態釋出,實時編譯生效,省略部署上線的過程。支援30個版本的歷史版本回溯。
- 20、指令碼任務:支援以GLUE模式開發和執行指令碼任務,包括Shell、Python、NodeJS、PHP、PowerShell等型別指令碼;
- 21、命令列任務:原生提供通用命令列任務Handler(Bean任務,"CommandJobHandler");業務方只需要提供命令列即可;
- 22、任務依賴:支援配置子任務依賴,當父任務執行結束且執行成功後將會主動觸發一次子任務的執行, 多個子任務用逗號分隔;
- 23、一致性:“排程中心”通過DB鎖保證叢集分散式排程的一致性, 一次任務排程只會觸發一次執行;
- 24、自定義任務引數:支援線上配置排程任務入參,即時生效;
- 25、排程執行緒池:排程系統多執行緒觸發排程執行,確保排程精確執行,不被堵塞;
- 26、資料加密:排程中心和執行器之間的通訊進行資料加密,提升排程資訊保安性;
- 27、郵件報警:任務失敗時支援郵件報警,支援配置多郵件地址群發報警郵件;
- 28、推送maven中央倉庫: 將會把最新穩定版推送到maven中央倉庫, 方便使用者接入和使用;
- 29、執行報表:支援實時檢視執行資料,如任務數量、排程次數、執行器數量等;以及排程報表,如排程日期分佈圖,排程成功分佈圖等;
- 30、全非同步:任務排程流程全非同步化設計實現,如非同步排程、非同步執行、非同步回撥等,有效對密集排程進行流量削峰,理論上支援任意時長任務的執行;
- 31、跨語言:排程中心與執行器提供語言無關的 RESTful API 服務,第三方任意語言可據此對接排程中心或者實現執行器。除此之外,還提供了 “多工模式”和“httpJobHandler”等其他跨語言方案;
- 32、國際化:排程中心支援國際化設定,提供中文、英文兩種可選語言,預設為中文;
- 33、容器化:提供官方docker映象,並實時更新推送dockerhub,進一步實現產品開箱即用;
- 34、執行緒池隔離:排程執行緒池進行隔離拆分,慢任務自動降級進入"Slow"執行緒池,避免耗盡排程執行緒,提高系統穩定性;
- 35、使用者管理:支援線上管理系統使用者,存在管理員、普通使用者兩種角色;
- 36、許可權控制:執行器維度進行許可權控制,管理員擁有全量許可權,普通使用者需要分配執行器許可權後才允許相關操作;
xxl-job的架構設計
設計思想
將排程行為抽象形成“排程中心”公共平臺,而平臺自身並不承擔業務邏輯,“排程中心”負責發起排程請求。
將任務抽象成分散的JobHandler,交由“執行器”統一管理,“執行器”負責接收排程請求並執行對應的JobHandler中業務邏輯。
因此,“排程”和“任務”兩部分可以相互解耦,提高系統整體穩定性和擴充套件性;
系統組成
- 排程模組(排程中心)
- 負責管理排程資訊,按照排程配置發出排程請求,自身不承擔業務程式碼。排程系統與任務解耦,提高了系統可用性和穩定性,同時排程系統性能不再受限於任務模組;
- 支援視覺化、簡單且動態的管理排程資訊,包括任務新建,更新,刪除,GLUE開發和任務報警等,所有上述操作都會實時生效,同時支援監控排程結果以及執行日誌,支援執行器Failover。
- 執行模組(執行器):
- 負責接收排程請求並執行任務邏輯。任務模組專注於任務的執行等操作,開發和維護更加簡單和高效;
- 接收“排程中心”的執行請求、終止請求和日誌請求等。
架構圖
實現案例
主要介紹SpringBoot整合xxl-job的方式:Bean模式(基於方法和基於類); 以及基於線上配置程式碼/指令碼的GLUE模式。
Bean模式(基於方法)
Bean模式任務,支援基於方法的開發方式,每個任務對應一個方法。基於方法開發的任務,底層會生成JobHandler代理,和基於類的方式一樣,任務也會以JobHandler的形式存在於執行器任務容器中。
優點:
- 每個任務只需要開發一個方法,並新增”@XxlJob”註解即可,更加方便、快速。
- 支援自動掃描任務並注入到執行器容器。
缺點:要求Spring容器環境;
Job的開發環境依賴
Maven 依賴
xml
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.1</version>
</dependency>
application.properties配置
```yml
web port
server.port=8081
no web
spring.main.web-environment=false
log config
logging.config=classpath:logback.xml
xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
xxl-job, access token
xxl.job.accessToken=default_token
xxl-job executor appname
xxl.job.executor.appname=xxl-job-executor-sample
xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
xxl-job executor server-info
xxl.job.executor.ip= xxl.job.executor.port=9999
xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30
```
Config配置(PS:這裡我是直接拿的xxl-job demo中的配置,實際開發中可以封裝一個starter自動注入)
```java package tech.pdai.springboot.xxljob.config;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
/* * xxl-job config * * @author xuxueli 2017-04-28 / @Configuration public class XxlJobConfig { private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
// Bean方法模式
// 通過掃描@XxlJob方式註冊
// 註冊Bean類模式
XxlJobExecutor.registJobHandler("beanClassDemoJobHandler", new BeanClassDemoJob());
return xxlJobSpringExecutor;
}
}
```
Job的開發
開發步驟:
- 任務開發:在Spring Bean例項中,開發Job方法;
- 註解配置:為Job方法添加註解 "@XxlJob(value="自定義jobhandler名稱", init = "JobHandler初始化方法", destroy = "JobHandler銷燬方法")",註解value值對應的是排程中心新建任務的JobHandler屬性的值。
- 執行日誌:需要通過 "XxlJobHelper.log" 列印執行日誌;
- 任務結果:預設任務結果為 "成功" 狀態,不需要主動設定;如有訴求,比如設定任務結果為失敗,可以通過 "XxlJobHelper.handleFail/handleSuccess" 自主設定任務結果;
```java package tech.pdai.springboot.xxljob.job;
import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.Arrays;
import com.xxl.job.core.context.XxlJobHelper; import com.xxl.job.core.handler.annotation.XxlJob; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;
/* * XxlJob開發示例(Bean模式 - 方法) * / @Slf4j @Component public class BeanMethodDemoJob {
/**
* 1、簡單任務示例(Bean模式)
*/
@XxlJob("demoJobHandler")
public void demoJobHandler() {
XxlJobHelper.log("demoJobHandler execute...");
}
/**
* 2、分片廣播任務
*/
@XxlJob("shardingJobHandler")
public void shardingJobHandler() throws Exception {
// logback console日誌
log.info("shardingJobHandler execute...");
// 通過xxl記錄到DB中的日誌
XxlJobHelper.log("shardingJobHandler execute...");
// 分片引數
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobHelper.log("分片引數:當前分片序號 = {}, 總分片數 = {}", shardIndex, shardTotal);
// 業務邏輯
for (int i = 0; i < shardTotal; i++) {
if (i==shardIndex) {
XxlJobHelper.log("第 {} 片, 命中分片開始處理", i);
} else {
XxlJobHelper.log("第 {} 片, 忽略", i);
}
}
}
/**
* 3、命令列任務
*/
@XxlJob("commandJobHandler")
public void commandJobHandler() throws Exception {
XxlJobHelper.log("commandJobHandler execute...");
String command = XxlJobHelper.getJobParam();
int exitValue = -1;
BufferedReader bufferedReader = null;
try {
// command process
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(command);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
//Process process = Runtime.getRuntime().exec(command);
BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));
// command log
String line;
while ((line = bufferedReader.readLine())!=null) {
XxlJobHelper.log(line);
}
// command exit
process.waitFor();
exitValue = process.exitValue();
} catch (Exception e) {
XxlJobHelper.log(e);
} finally {
if (bufferedReader!=null) {
bufferedReader.close();
}
}
if (exitValue==0) {
// default success
} else {
XxlJobHelper.handleFail("command exit value(" + exitValue + ") is failed");
}
}
/**
* 4、跨平臺Http任務
* 引數示例:
* "url: http://www.baidu.com\n" +
* "method: get\n" +
* "data: content\n";
*/
@XxlJob("httpJobHandler")
public void httpJobHandler() throws Exception {
XxlJobHelper.log("httpJobHandler execute...");
// param parse
String param = XxlJobHelper.getJobParam();
if (param==null || param.trim().length()==0) {
XxlJobHelper.log("param[" + param + "] invalid.");
XxlJobHelper.handleFail();
return;
}
String[] httpParams = param.split("\n");
String url = null;
String method = null;
String data = null;
for (String httpParam : httpParams) {
if (httpParam.startsWith("url:")) {
url = httpParam.substring(httpParam.indexOf("url:") + 4).trim();
}
if (httpParam.startsWith("method:")) {
method = httpParam.substring(httpParam.indexOf("method:") + 7).trim().toUpperCase();
}
if (httpParam.startsWith("data:")) {
data = httpParam.substring(httpParam.indexOf("data:") + 5).trim();
}
}
// param valid
if (url==null || url.trim().length()==0) {
XxlJobHelper.log("url[" + url + "] invalid.");
XxlJobHelper.handleFail();
return;
}
if (method==null || !Arrays.asList("GET", "POST").contains(method)) {
XxlJobHelper.log("method[" + method + "] invalid.");
XxlJobHelper.handleFail();
return;
}
boolean isPostMethod = method.equals("POST");
// request
HttpURLConnection connection = null;
BufferedReader bufferedReader = null;
try {
// connection
URL realUrl = new URL(url);
connection = (HttpURLConnection) realUrl.openConnection();
// connection setting
connection.setRequestMethod(method);
connection.setDoOutput(isPostMethod);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setReadTimeout(5 * 1000);
connection.setConnectTimeout(3 * 1000);
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
connection.setRequestProperty("Accept-Charset", "application/json;charset=UTF-8");
// do connection
connection.connect();
// data
if (isPostMethod && data!=null && data.trim().length() > 0) {
DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
dataOutputStream.write(data.getBytes("UTF-8"));
dataOutputStream.flush();
dataOutputStream.close();
}
// valid StatusCode
int statusCode = connection.getResponseCode();
if (statusCode!=200) {
throw new RuntimeException("Http Request StatusCode(" + statusCode + ") Invalid.");
}
// result
bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
StringBuilder result = new StringBuilder();
String line;
while ((line = bufferedReader.readLine())!=null) {
result.append(line);
}
String responseMsg = result.toString();
XxlJobHelper.log(responseMsg);
return;
} catch (Exception e) {
XxlJobHelper.log(e);
XxlJobHelper.handleFail();
return;
} finally {
try {
if (bufferedReader!=null) {
bufferedReader.close();
}
if (connection!=null) {
connection.disconnect();
}
} catch (Exception e2) {
XxlJobHelper.log(e2);
}
}
}
/**
* 5、生命週期任務示例:任務初始化與銷燬時,支援自定義相關邏輯;
*/
@XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
public void demoJobHandler2() throws Exception {
XxlJobHelper.log("demoJobHandler2, execute...");
}
public void init() {
log.info("init");
}
public void destroy() {
log.info("destroy");
}
}
```
(@pdai: 從設計的角度,xxl-job可以對上述不同型別進行細分)
Job的排程配置和執行
新增Job, 並把上述的@XxlJob(value="自定義jobhandler名稱", init = "JobHandler初始化方法", destroy = "JobHandler銷燬方法")中 自定義jobhandler名稱 填寫到JobHandler中。
其它配置如下:
可以選擇操作中執行一次任務,或者啟動(按照Cron執行)
可以檢視執行的記錄
進一步可以看每個執行記錄的執行日誌
Bean模式(基於類)
Bean模式任務,支援基於類的開發方式,每個任務對應一個Java類。
優點:不限制專案環境,相容性好。即使是無框架專案,如main方法直接啟動的專案也可以提供支援,可以參考示例專案 “xxl-job-executor-sample-frameless”;
缺點:
- 每個任務需要佔用一個Java類,造成類的浪費;
- 不支援自動掃描任務並注入到執行器容器,需要手動注入。
Job的開發環境依賴
同Bean模式(基於方法)
Job的開發
開發步驟:
- 執行器專案中,開發Job類:
- 開發一個繼承自"com.xxl.job.core.handler.IJobHandler"的JobHandler類,實現其中任務方法。
- 手動通過如下方式注入到執行器容器。
- 註冊jobHandler
XxlJobExecutor.registJobHandler("xxxxxJobHandler", new xxxxxJobHandler());
Job開發
```java package tech.pdai.springboot.xxljob.job;
import com.xxl.job.core.handler.IJobHandler; import lombok.extern.slf4j.Slf4j;
/* * @author pdai / @Slf4j public class BeanClassDemoJob extends IJobHandler {
@Override
public void execute() throws Exception {
log.info("BeanClassDemoJob, execute...");
}
} ```
註冊jobHandler(@pdai: 這裡xxl-job設計的不好,是可以通過IJobHandler來自動註冊的)
java
XxlJobExecutor.registJobHandler("beanClassDemoJobHandler", new BeanClassDemoJob());
啟動SpringBoot應用, 可以發現註冊的
java
...
20:34:15.385 logback [main] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job register jobhandler success, name:beanClassDemoJobHandler, jobHandler:tech.pdai.springboot.xxljob.job.BeanClassDemoJob@640ab13c
...
Job的排程配置和執行
同Bean模式(基於方法)
在排程器中新增執行後,後臺執行的日誌如下:
java
20:41:00.021 logback [xxl-job, EmbedServer bizThreadPool-1023773196] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job regist JobThread success, jobId:5, handler:tech.pdai.springboot.xxljob.job.BeanClassDemoJob@640ab13c
20:41:00.022 logback [xxl-job, JobThread-5-1654681260021] INFO t.p.s.xxljob.job.BeanClassDemoJob - BeanClassDemoJob, execute...
GLUE模式
任務以原始碼方式維護在排程中心,支援通過Web IDE線上更新,實時編譯和生效,因此不需要指定JobHandler。
配置和啟動流程
開發流程如下:
建立GLUE型別的Job(這裡以Java為例)
選中指定任務,點選該任務右側“GLUE”按鈕,將會前往GLUE任務的Web IDE介面,在該介面支援對任務程式碼進行開發(也可以在IDE中開發完成後,複製貼上到編輯中)。
版本回溯功能(支援30個版本的版本回溯):在GLUE任務的Web IDE介面,選擇右上角下拉框“版本回溯”,會列出該GLUE的更新歷史,選擇相應版本即可顯示該版本程式碼,儲存後GLUE程式碼即回退到對應的歷史版本;
執行後的記錄如下
GLUE模式還有哪些
xxl-job一共支援如下幾種GLUE模式:
- GLUE模式(Java):任務以原始碼方式維護在排程中心;該模式的任務實際上是一段繼承自IJobHandler的Java類程式碼並 "groovy" 原始碼方式維護,它在執行器專案中執行,可使用@Resource/@Autowire注入執行器裡中的其他服務;
- GLUE模式(Shell):任務以原始碼方式維護在排程中心;該模式的任務實際上是一段 "shell" 指令碼;
- GLUE模式(Python):任務以原始碼方式維護在排程中心;該模式的任務實際上是一段 "python" 指令碼;
- GLUE模式(PHP):任務以原始碼方式維護在排程中心;該模式的任務實際上是一段 "php" 指令碼;
- GLUE模式(NodeJS):任務以原始碼方式維護在排程中心;該模式的任務實際上是一段 "nodejs" 指令碼;
- GLUE模式(PowerShell):任務以原始碼方式維護在排程中心;該模式的任務實際上是一段 "PowerShell" 指令碼;
更多配置的說明
```bash + 基礎配置: - 執行器:任務的繫結的執行器,任務觸發排程時將會自動發現註冊成功的執行器, 實現任務自動發現功能; 另一方面也可以方便的進行任務分組。每個任務必須繫結一個執行器, 可在 "執行器管理" 進行設定; - 任務描述:任務的描述資訊,便於任務管理; - 負責人:任務的負責人; - 報警郵件:任務排程失敗時郵件通知的郵箱地址,支援配置多郵箱地址,配置多個郵箱地址時用逗號分隔;
- 觸發配置:
- 排程型別:
- 無:該型別不會主動觸發排程;
- CRON:該型別將會通過CRON,觸發任務排程;
- 固定速度:該型別將會以固定速度,觸發任務排程;按照固定的間隔時間,週期性觸發;
- 固定延遲:該型別將會以固定延遲,觸發任務排程;按照固定的延遲時間,從上次排程結束後開始計算延遲時間,到達延遲時間後觸發下次排程;
- CRON:觸發任務執行的Cron表示式;
- 固定速度:韌體速度的時間間隔,單位為秒;
-
固定延遲:韌體延遲的時間間隔,單位為秒;
-
高階配置:
- 路由策略:當執行器叢集部署時,提供豐富的路由策略,包括; FIRST(第一個):固定選擇第一個機器; LAST(最後一個):固定選擇最後一個機器; ROUND(輪詢):; RANDOM(隨機):隨機選擇線上的機器; CONSISTENT_HASH(一致性HASH):每個任務按照Hash演算法固定選擇某一臺機器,且所有任務均勻雜湊在不同機器上。 LEAST_FREQUENTLY_USED(最不經常使用):使用頻率最低的機器優先被選舉; LEAST_RECENTLY_USED(最近最久未使用):最久未使用的機器優先被選舉; FAILOVER(故障轉移):按照順序依次進行心跳檢測,第一個心跳檢測成功的機器選定為目標執行器併發起排程; BUSYOVER(忙碌轉移):按照順序依次進行空閒檢測,第一個空閒檢測成功的機器選定為目標執行器併發起排程; SHARDING_BROADCAST(分片廣播):廣播觸發對應叢集中所有機器執行一次任務,同時系統自動傳遞分片引數;可根據分片引數開發分片任務;
- 子任務:每個任務都擁有一個唯一的任務ID(任務ID可以從任務列表獲取),當本任務執行結束並且執行成功時,將會觸發子任務ID所對應的任務的一次主動排程。
- 排程過期策略:
- 忽略:排程過期後,忽略過期的任務,從當前時間開始重新計算下次觸發時間;
- 立即執行一次:排程過期後,立即執行一次,並從當前時間開始重新計算下次觸發時間;
- 阻塞處理策略:排程過於密集執行器來不及處理時的處理策略; 單機序列(預設):排程請求進入單機執行器後,排程請求進入FIFO佇列並以序列方式執行; 丟棄後續排程:排程請求進入單機執行器後,發現執行器存在執行的排程任務,本次請求將會被丟棄並標記為失敗; 覆蓋之前排程:排程請求進入單機執行器後,發現執行器存在執行的排程任務,將會終止執行中的排程任務並清空佇列,然後執行本地排程任務;
- 任務超時時間:支援自定義任務超時時間,任務執行超時將會主動中斷任務;
- 失敗重試次數;支援自定義任務失敗重試次數,當任務失敗時將會按照預設的失敗重試次數主動進行重試; ```
示例原始碼
http://github.com/realpdai/tech-pdai-spring-demos
更多內容
告別碎片化學習,無套路一站式體系化學習後端開發: Java 全棧知識體系 http://pdai.tech
- SpringBoot定時任務 - 開箱即用分散式任務框架xxl-job
- SpringBoot開發 - 什麼是熱部署和熱載入?devtool的原理是什麼?
- Spring框架系列(13) - SpringMVC實現原理之DispatcherServlet的初始化過程
- Spring框架系列(11) - Spring AOP實現原理詳解之Cglib代理實現
- Spring框架系列(9) - Spring AOP實現原理詳解之AOP切面的實現
- Spring框架系列(8) - Spring IOC實現原理詳解之Bean例項化(生命週期,迴圈依賴等)
- Spring框架系列(7) - Spring IOC實現原理詳解之IOC初始化流程
- Spring框架系列(3) - 深入淺出Spring核心之控制反轉(IOC)