Merge branch 'master' into feature/timeout

This commit is contained in:
许雪里 2018-06-24 15:49:34 +08:00 committed by GitHub
commit c3c7ded5e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 393 additions and 159 deletions

View File

@ -156,6 +156,36 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
- 64、未来无线网
- 65、厦门瓷禧网络有限公司
- 66、北京递蓝科软件股份有限公司
- 67、郑州创海软件科技公司
- 68、北京国槐信息科技有限公司
- 69、浪潮软件集团
- 70、多立恒(北京)信息技术有限公司
- 71、广州极迅客信息科技有限公司
- 72、赫基中国集团股份有限公司
- 73、海投汇
- 74、上海润益创业孵化器管理股份有限公司
- 75、汉纳森厦门数据股份有限公司
- 76、安信信托
- 77、岚儒财富
- 78、捷道软件
- 79、湖北享七网络科技有限公司
- 80、湖南创发科技责任有限公司
- 81、深圳小安时代互联网金融服务有限公司
- 82、湖北享七网络科技有限公司
- 83、钱包行云(北京)科技有限公司
- 84、360金融 (360)
- 85、易企秀
- 86、摩贝上海生物科技有限公司
- 87、广东芯智慧科技有限公司
- 88、联想集团 (联想)
- 89、怪兽充电
- 90、行圆汽车
- 91、深圳店店通科技邮箱公司
- 92、京东 (京东)
- 93、米庄理财
- 94、咖啡易融
- 95、梧桐诚选
- 96、恒大地产 (恒大)
- ……
> 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。

View File

@ -121,6 +121,35 @@ So far, XXL-JOB has access to a number of companies online product line, access
- 65、厦门瓷禧网络有限公司
- 66、北京递蓝科软件股份有限公司
- 67、郑州创海软件科技公司
- 68、北京国槐信息科技有限公司
- 69、浪潮软件集团
- 70、多立恒(北京)信息技术有限公司
- 71、广州极迅客信息科技有限公司
- 72、赫基中国集团股份有限公司
- 73、海投汇
- 74、上海润益创业孵化器管理股份有限公司
- 75、汉纳森厦门数据股份有限公司
- 76、安信信托
- 77、岚儒财富
- 78、捷道软件
- 79、湖北享七网络科技有限公司
- 80、湖南创发科技责任有限公司
- 81、深圳小安时代互联网金融服务有限公司
- 82、湖北享七网络科技有限公司
- 83、钱包行云(北京)科技有限公司
- 84、360金融 (360)
- 85、易企秀
- 86、摩贝上海生物科技有限公司
- 87、广东芯智慧科技有限公司
- 88、联想集团 (联想)
- 89、怪兽充电
- 90、行圆汽车
- 91、深圳店店通科技邮箱公司
- 92、京东 (京东)
- 93、米庄理财
- 94、咖啡易融
- 95、梧桐诚选
- 96、恒大地产 (恒大)
- ……
> The company that access and use this product is welcome to register at the [address](https://github.com/xuxueli/xxl-job/issues/1 ), only for product promotion.
@ -227,7 +256,7 @@ The concrete contet describe as follows:
If you has finished step 1,then you can compile the project in maven and deploy the war package to tomcat.
the url to visit is :http://localhost:8080/xxl-job-admin (this address will be used by executor and use it as callback url),the index page after login in is as follow
![index page after login in](https://static.oschina.net/uploads/img/201705/08194505_6yC0.png "index page after login in")
![index page after login in](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_6yC0.png "index page after login in")
Now,the “xxl-job-admin” project is deployed success.
@ -321,16 +350,16 @@ Now lets create a "GLUE模式(Java)" job,if you want to learn more about it ,
#### Step 1:Create new job
Login in xxl-job-admin,click on the"新建任务" button, configure the job params as follows and click "保存" button to save the job info.
![task management](https://static.oschina.net/uploads/img/201704/27205910_o8HQ.png "task management")
![task management](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_o8HQ.png "task management")
![create task](https://static.oschina.net/uploads/img/201704/27210202_SE2u.png "create task")
![create task](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_ZAsz.png "create task")
#### Step 2develop “GLUE模式(Java)” job
Click “GLUE” button on the right of the job to go to GLUE editor view as shown below。“GLUE模式(Java)” mode task has been inited with default task code for printing Hello World。 “GLUE模式(Java)” mode task is a java code fragment implements IJobHandler interface,it will be executed in executor,you can use @Resource/@Autowire to inject other java bean instance,if you want to see more info please go to chapter 3
![输入图片说明](https://static.oschina.net/uploads/img/201704/27210307_Fgql.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Fgql.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201704/27210314_dNUJ.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_dNUJ.png "在这里输入图片标题")
#### Step 3:trigger task
If you want to run the job manually please click "执行" button on the right of the job(usually we trigger job by Cron expression)
@ -338,11 +367,11 @@ If you want to run the job manually please click "执行" button on the right of
#### Step 4:view log
Click “日志” button on the right side of the task you will go to the task log list ,you will see the schedule history records of the task and the schedule detail info,execution info and execution params.If you click the “执行日志” button on the right side of the task log record,you will go to log console and view the execute log in the course of task execution.
![输入图片说明](https://static.oschina.net/uploads/img/201704/27232850_inc8.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_inc8.png "在这里输入图片标题")
On the log console,you can view task execution log on the executor immediately after it dump to log file,so you can monitor the task execution process by Rolling way.
![输入图片说明](https://static.oschina.net/uploads/img/201704/27211631_eYrv.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_eYrv.png "在这里输入图片标题")
## 3. Task details
@ -390,12 +419,12 @@ The task logic exist in the executor project as JobHandler,the develop steps as
- 3, add “@JobHandler(value=" customize jobhandler name")” annotationthe value stand for JobHandler name,it will be used as JobHandler property when create a new task in the schedule center.
go and see DemoJobHandler in the xxl-job-executor-example project, as shown below
![输入图片说明](https://static.oschina.net/uploads/img/201607/23232347_oLlM.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_oLlM.png "在这里输入图片标题")
#### Step 2:create task in schedule center
If you want learn more about configure item please go and sedd “Description of configuration item”select "BEAN模式" as run modeproperty JobHandler please fill in the value defined by @JobHande.
![输入图片说明](https://static.oschina.net/uploads/img/201704/27225124_yrcO.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_ZAsz.png "在这里输入图片标题")
### 3.2 GLUE模式(Java)
Task source code is maintained in the schedule center and can be updated by Web IDE online, it will be compiled and effective real-time,didnt need to assign JobHandler,develop flow shown as below:
@ -403,14 +432,14 @@ Task source code is maintained in the schedule center and can be updated by Web
#### Step 1:create task in schedule center
If you want learn more about configure item please go and sedd “Description of configuration item”select "GLUE模式(Java)" as run mode.
![输入图片说明](https://static.oschina.net/uploads/img/201704/27210202_SE2u.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_tJOq.png "在这里输入图片标题")
#### Step 2:develop task source code
Select the task record and click “GLUE” button on the righe of it,it will go to GLUE tasks WEB IDE page,on this page yo can edit you task code(also can edit in other IDE tools,copy and paste into this page).
Version backtracksupport 30 versions while backtrackon the WEB IDE page of GLUE task,on upper right corner drop down box please select “版本回溯”,it will display GLUE updated history,select the version you want it will display the source code of this version,it will backtrace the version while click save button.
![输入图片说明](https://static.oschina.net/uploads/img/201704/27210314_dNUJ.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_dNUJ.png "在这里输入图片标题")
### 3.3 GLUE模式(Shell)
@ -422,7 +451,7 @@ Select the task record and click “GLUE” button on the righe of it,it will go
Actually it is a shell script fragment.
![输入图片说明](https://static.oschina.net/uploads/img/201704/27232259_iUw0.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_iUw0.png "在这里输入图片标题")
### 3.4 GLUE模式(Python)
@ -434,19 +463,19 @@ Select the task record and click “GLUE” button on the righe of it,it will go
Actually it is a python script fragment.
![输入图片说明](https://static.oschina.net/uploads/img/201704/27232305_BPLG.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_BPLG.png "在这里输入图片标题")
## 4. Task Management
### 4.0 configure executor
click"执行器管理" on the left menu,it will go to the page as shown below:
![输入图片说明](https://static.oschina.net/uploads/img/201703/12223509_Hr2T.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Hr2T.png "在这里输入图片标题")
   1,"调度中心OnLine”:display schedule center machine list,when task is scheduled it will callback schedule center for notify the execution result in failover mode, so that it can avoid a single point scheduler;
   2,"执行器列表" :display all nodes under this executor group.
If you want to create a new executor,please click "+新增执行器" button:
![输入图片说明](https://static.oschina.net/uploads/img/201703/12223617_g3Im.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_V3vF.png "在这里输入图片标题")
### Description of executor attributes
@ -473,19 +502,19 @@ choose the task you want to edit and click” GLUE”button on the right side of
### 4.4 pause/recover task
You can pause or recover task but it just fit to follow up schedule trigger and wont affect scheduled tasks,if you want to stop tasks which has been triggered,please go and see “4.8 stop the running task”
![输入图片说明](https://static.oschina.net/uploads/img/201607/24130337_ZAhX.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_ZAhX.png "在这里输入图片标题")
### 4.5 manually trigger
You can trigger a task manually by Click “执行”button,it wont affect original scheduling rules.
![输入图片说明](https://static.oschina.net/uploads/img/201607/24133348_Z5wp.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Z5wp.png "在这里输入图片标题")
### 4.6 view schedule log
You can view tasks history schedule log by click “日志” button,on the history schedule log list page you can view every time of tasks schedule result,execution result and so on,click “执行日志” button can view the tasks full execute log.
![输入图片说明](https://static.oschina.net/uploads/img/201607/24133500_9235.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_9235.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201704/27232850_inc8.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_inc8.png "在这里输入图片标题")
调度时间:schedule center trigger time when schedule and send execution signal to executor;
调度结果:schedule center trigger tasks result, 200 represent success,500 or other number stands for fail;
@ -503,12 +532,12 @@ You can view tasks history schedule log by click “日志” button,on the h
### 4.7 view execution log
Click the “执行日志” button on the right side of the record,you can go to the execution log page,you can view the full execution log of the logic business code, shown as below:
![输入图片说明](https://static.oschina.net/uploads/img/201703/25124816_tvGI.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_tvGI.png "在这里输入图片标题")
### 4.8 stop running tasks
Just fit to running tasks,on the task log list page,click “终止任务” button on the right side of the record, it will send stop command to the executor where the task was executed,finally the task was killed and the task instance execute queue of this task will be clear.
![输入图片说明](https://static.oschina.net/uploads/img/201607/24140048_hIci.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_hIci.png "在这里输入图片标题")
It is implemented by interrupt execute thread, it will trigger InterruptedException.so if JobHandler catch this execuption and handle this exception this function is unavailable.
@ -529,14 +558,14 @@ If JobHandler start child thread,child thread also must not catch InterruptedExc
### 4.9 delete execution log
On the task log list page, after you select executor and task, you can click"删除" button on the right side and it will pop-up "日志清理" window,on the pop-up window you can choose different log delete policy,choose the policy you want to execute and click "确定" button it will delele relative logs:
![输入图片说明](https://static.oschina.net/uploads/img/201705/08210711_Ypik.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Ypik.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201705/08211152_EB65.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_EB65.png "在这里输入图片标题")
### 4.10 delete task
Click the delete button on the right side of the task,the task will be deteted.
![输入图片说明](https://static.oschina.net/uploads/img/201607/24140641_Z9Qr.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Z9Qr.png "在这里输入图片标题")
## 5. Overall design
### 5.1 Source directory introduction
@ -551,7 +580,7 @@ XXL-JOB schedule module is implemented based on Quartz cluster,its “databas
XXL-JOB custom Quartz table structure prefix(XXL_JOB_QRTZ_).
![输入图片说明](https://static.oschina.net/uploads/img/201607/24143957_bNwm.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_bNwm.png "在这里输入图片标题")
The added tables as shown below:
- XXL_JOB_QRTZ_TRIGGER_GROUP:executor basic table, maintain the info about the executor;
@ -580,7 +609,7 @@ So schedule and task can be decoupled from each other, by the way it can improve
#### 5.3.3 Architecture diagram
![输入图片说明](https://static.oschina.net/uploads/img/201707/17190028_aEE2.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Qohm.png "在这里输入图片标题")
### 5.4 Schedule module analysis
#### 5.4.1 Disadvantage of quartz
@ -661,10 +690,9 @@ Executor will execute task when it receive task execute request.it will notify t
If executor project was deployed as cluster schedule center will known all online executor nodes,such as:“127.0.0.1:9997, 127.0.0.1:9998, 127.0.0.1:9999”.
When "路由策略" select "故障转移(FAILOVER)",it will send heart beat check request in order while schedule center start schedule request. The first alive checked executor node will be selected and send schedule request to it.
![输入图片说明](https://static.oschina.net/uploads/img/201705/11221144_P128.png "在这里输入图片标题")
“调度备注” can be viewed on the monitor page when schedule success. As shown below:
![输入图片说明](https://static.oschina.net/uploads/img/201703/12230733_jrdI.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_jrdI.png "在这里输入图片标题")
“调度备注” will display local schedule route path、executors "注册方式"、"地址列表" and tasks "路由策略"。Under "故障转移(FAILOVER)" policy, schedule center take first address to do heartbeat detection, heat beat fail will automatically skip, the second address heart beat fail…… until the third address “127.0.0.1:9999” heart beat success, it was selected as target executor, then send schedule request to target executor, now the schedule process is end wait for the executors callback execution result.
@ -675,8 +703,6 @@ Every time when task was scheduled in the schedule center it will record a task
- 调度信息:include schedule time、schedule result and schedule log and so onaccord these parameters you can understand some task schedule info of schedule center.
- 执行信息:include execute time、execute result and execute log and so on, accord these parameters you can understand the task execution info in the executor.
![输入图片说明](https://static.oschina.net/uploads/img/201703/12221436_c8Ru.png "在这里输入图片标题")
Schedule log stands fo single task schedule, attribute description is as follows:
- 执行器地址:machine addresses on which task will be executed.
- JobHandler:JobHandler name of task under Bean module.
@ -696,9 +722,9 @@ When parent task end execute and success, it will match child task dependency ac
On the task log page ,you can see matched child task and triggered child tasks log info when you “查看”button of “执行备注”,otherwise the child task didint execute, as shown beleow:
![输入图片说明](https://static.oschina.net/uploads/img/201607/24194134_Wb2o.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Wb2o.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201607/24194212_jOAU.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_jOAU.png "在这里输入图片标题")
### 5.5 Task "run mode" analysis
#### 5.5.1 "Bean模式" task
@ -722,8 +748,6 @@ All supported types of scripts as shown beloes:
#### 5.5.4 executor
Executor is actually an embedded Jetty server with default port 9999, as shown belowparameter:xxl.job.executor.port.
![输入图片说明](https://static.oschina.net/uploads/img/201703/10174923_TgNO.png "在这里输入图片标题")
Executor will identify Bean mode task in spring container through @JobHandler When project start, it will be managed use the value of annotation as key.
When executor received schedule request from schedule center, if task type is “Bean模式” it will match bean mode task in Spring container and call its execute() method and execute task logic. if task type is “GLUE模式”, it will load Glue code, instantiate a Java object and inject other spring servicenotice: the spring service injected in Glue code must exist in the same executor project, then call execute() method and execute task logic.
@ -797,7 +821,7 @@ The scheduling center provides API services for executors and business parties t
The scheduling center API service location: com.xxl.job.core.biz.AdminBiz.java
The scheduling center API service requests reference codecom.xxl.job.dao.impl.AdminBizTest.java
The scheduling center API service requests reference codecom.xxl.job.adminbiz.AdminBizTest.java
## 6 Version update log

View File

@ -134,6 +134,35 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
- 65、厦门瓷禧网络有限公司
- 66、北京递蓝科软件股份有限公司
- 67、郑州创海软件科技公司
- 68、北京国槐信息科技有限公司
- 69、浪潮软件集团
- 70、多立恒(北京)信息技术有限公司
- 71、广州极迅客信息科技有限公司
- 72、赫基中国集团股份有限公司
- 73、海投汇
- 74、上海润益创业孵化器管理股份有限公司
- 75、汉纳森厦门数据股份有限公司
- 76、安信信托
- 77、岚儒财富
- 78、捷道软件
- 79、湖北享七网络科技有限公司
- 80、湖南创发科技责任有限公司
- 81、深圳小安时代互联网金融服务有限公司
- 82、湖北享七网络科技有限公司
- 83、钱包行云(北京)科技有限公司
- 84、360金融 (360)
- 85、易企秀
- 86、摩贝上海生物科技有限公司
- 87、广东芯智慧科技有限公司
- 88、联想集团 (联想)
- 89、怪兽充电
- 90、行圆汽车
- 91、深圳店店通科技邮箱公司
- 92、京东 (京东)
- 93、米庄理财
- 94、咖啡易融
- 95、梧桐诚选
- 96、恒大地产 (恒大)
- ……
> 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。
@ -227,6 +256,7 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
### 报警邮箱
xxl.job.mail.host=smtp.163.com
xxl.job.mail.port=25
xxl.job.mail.ssl=false
xxl.job.mail.username=ovono802302@163.com
xxl.job.mail.password=asdfzxcv
xxl.job.mail.sendFrom=ovono802302@163.com
@ -246,7 +276,7 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
如果已经正确进行上述配置可将项目编译打war包并部署到tomcat中。
调度中心访问地址http://localhost:8080/xxl-job-admin (该地址执行器将会使用到,作为回调地址),登录后运行界面如下图所示
![输入图片说明](https://static.oschina.net/uploads/img/201705/08194505_6yC0.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_6yC0.png "在这里输入图片标题")
至此“调度中心”项目已经部署成功。
@ -351,18 +381,18 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
#### 步骤一:新建任务:
登录调度中心,点击下图所示“新建任务”按钮,新建示例任务。然后,参考下面截图中任务的参数配置,点击保存。
![输入图片说明](https://static.oschina.net/uploads/img/201704/27205910_o8HQ.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_o8HQ.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201712/25183654_ZAsz.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_ZAsz.png "在这里输入图片标题")
#### 步骤二“GLUE模式(Java)” 任务开发:
请点击任务右侧 “GLUE” 按钮,进入 “GLUE编辑器开发界面” 见下图。“GLUE模式(Java)” 运行模式的任务默认已经初始化了示例任务代码即打印Hello World。
“GLUE模式(Java)” 运行模式的任务实际上是一段继承自IJobHandler的Java类代码它在执行器项目中运行可使用@Resource/@Autowire注入执行器里中的其他服务详细介绍请查看第三章节
![输入图片说明](https://static.oschina.net/uploads/img/201704/27210307_Fgql.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Fgql.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201704/27210314_dNUJ.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_dNUJ.png "在这里输入图片标题")
#### 步骤三:触发执行:
请点击任务右侧 “执行” 按钮可手动触发一次任务执行通常情况下通过配置Cron表达式进行任务调度出发
@ -371,11 +401,11 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
请点击任务右侧 “日志” 按钮,可前往任务日志界面查看任务日志。
在任务日志界面中,可查看该任务的历史调度记录以及每一次调度的任务调度信息、执行参数和执行信息。运行中的任务点击右侧的“执行日志”按钮,可进入日志控制台查看实时执行日志。
![输入图片说明](https://static.oschina.net/uploads/img/201704/27232850_inc8.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_inc8.png "在这里输入图片标题")
在日志控制台可以Rolling方式实时查看任务在执行器一侧运行输出的日志信息实时监控任务进度
![输入图片说明](https://static.oschina.net/uploads/img/201704/27211631_eYrv.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_eYrv.png "在这里输入图片标题")
## 三、任务详解
@ -426,12 +456,12 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
- 4、执行日志需要通过 "XxlJobLogger.log" 打印执行日志;
可参考Sample示例执行器中的DemoJobHandler见下图
![输入图片说明](https://static.oschina.net/uploads/img/201607/23232347_oLlM.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_oLlM.png "在这里输入图片标题")
#### 步骤二:调度中心,新建调度任务
参考上文“配置属性详细说明”对新建的任务进行参数配置,运行模式选中 "BEAN模式"JobHandler属性填写任务注解“@JobHandler”中定义的值
![输入图片说明](https://static.oschina.net/uploads/img/201712/25183654_ZAsz.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_ZAsz.png "在这里输入图片标题")
### 3.2 GLUE模式(Java)
任务以源码方式维护在调度中心支持通过Web IDE在线更新实时编译和生效因此不需要指定JobHandler。开发流程如下
@ -439,14 +469,14 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
#### 步骤一:调度中心,新建调度任务:
参考上文“配置属性详细说明”对新建的任务进行参数配置,运行模式选中 "GLUE模式(Java)"
![输入图片说明](https://static.oschina.net/uploads/img/201712/25183837_tJOq.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_tJOq.png "在这里输入图片标题")
#### 步骤二:开发任务代码:
选中指定任务点击该任务右侧“GLUE”按钮将会前往GLUE任务的Web IDE界面在该界面支持对任务代码进行开发也可以在IDE中开发完成后复制粘贴到编辑中
版本回溯功能支持30个版本的版本回溯在GLUE任务的Web IDE界面选择右上角下拉框“版本回溯”会列出该GLUE的更新历史选择相应版本即可显示该版本代码保存后GLUE代码即回退到对应的历史版本
![输入图片说明](https://static.oschina.net/uploads/img/201704/27210314_dNUJ.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_dNUJ.png "在这里输入图片标题")
### 3.3 GLUE模式(Shell)
@ -458,7 +488,7 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
该模式的任务实际上是一段 "shell" 脚本;
![输入图片说明](https://static.oschina.net/uploads/img/201704/27232259_iUw0.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_iUw0.png "在这里输入图片标题")
### 3.4 GLUE模式(Python)
@ -470,7 +500,7 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
该模式的任务实际上是一段 "python" 脚本;
![输入图片说明](https://static.oschina.net/uploads/img/201704/27232305_BPLG.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_BPLG.png "在这里输入图片标题")
### 3.5 GLUE模式(NodeJS)
@ -487,14 +517,14 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
### 4.0 配置执行器
点击进入"执行器管理"界面, 如下图:
![输入图片说明](https://static.oschina.net/uploads/img/201703/12223509_Hr2T.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Hr2T.png "在这里输入图片标题")
1、"调度中心OnLine:"右侧显示在线的"调度中心"列表, 任务执行结束后, 将会以failover的模式进行回调调度中心通知执行结果, 避免回调的单点风险;
2、"执行器列表" 中显示在线的执行器列表, 可通过"OnLine 机器"查看对应执行器的集群机器。
点击按钮 "+新增执行器" 弹框如下图, 可新增执行器配置:
![输入图片说明](https://static.oschina.net/uploads/img/201712/25183958_V3vF.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_V3vF.png "在这里输入图片标题")
### 执行器属性说明
@ -522,19 +552,19 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
可对任务进行“暂停”和“恢复”操作。
需要注意的是,此处的暂停/恢复仅针对任务的后续调度触发行为不会影响到已经触发的调度任务如需终止已经触发的调度任务可查看“4.8 终止运行中的任务”
![输入图片说明](https://static.oschina.net/uploads/img/201607/24130337_ZAhX.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_ZAhX.png "在这里输入图片标题")
### 4.5 手动触发一次调度
点击“执行”按钮,可手动触发一次任务调度,不影响原有调度规则。
![输入图片说明](https://static.oschina.net/uploads/img/201607/24133348_Z5wp.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Z5wp.png "在这里输入图片标题")
### 4.6 查看调度日志
点击“日志”按钮,可以查看任务历史调度日志。在历史调入日志界面可查看每次任务调度的调度结果、执行结果等,点击“执行日志”按钮可查看执行器完整日志。
![输入图片说明](https://static.oschina.net/uploads/img/201607/24133500_9235.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_9235.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201712/25184206_UDSo.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_UDSo.png "在这里输入图片标题")
调度时间:"调度中心"触发本次调度并向"执行器"发送任务执行信号的时间;
调度结果:"调度中心"触发本次调度的结果200表示成功500或其他表示失败
@ -552,13 +582,13 @@ XXL-JOB是一个轻量级分布式任务调度框架其核心设计目标是
### 4.7 查看执行日志
点击执行日志右侧的 “执行日志” 按钮,可跳转至执行日志界面,可以查看业务代码中打印的完整日志,如下图;
![输入图片说明](https://static.oschina.net/uploads/img/201703/25124816_tvGI.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_tvGI.png "在这里输入图片标题")
### 4.8 终止运行中的任务
仅针对执行中的任务。
在任务日志界面,点击右侧的“终止任务”按钮,将会向本次任务对应的执行器发送任务终止请求,将会终止掉本次任务,同时会清空掉整个任务执行队列。
![输入图片说明](https://static.oschina.net/uploads/img/201607/24140048_hIci.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_hIci.png "在这里输入图片标题")
任务终止时通过 "interrupt" 执行线程的方式实现, 将会触发 "InterruptedException" 异常。因此如果JobHandler内部catch到了该异常并消化掉的话, 任务终止功能将不可用。
@ -579,14 +609,14 @@ try{
### 4.9 删除执行日志
在任务日志界面,选中执行器和任务之后,点击右侧的"删除"按钮将会出现"日志清理"弹框,弹框中支持选择不同类型的日志清理策略,选中后点击"确定"按钮即可进行日志清理操作;
![输入图片说明](https://static.oschina.net/uploads/img/201705/08210711_Ypik.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Ypik.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201705/08211152_EB65.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_EB65.png "在这里输入图片标题")
### 4.10 删除任务
点击删除按钮,可以删除对应任务。
![输入图片说明](https://static.oschina.net/uploads/img/201607/24140641_Z9Qr.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Z9Qr.png "在这里输入图片标题")
## 五、总体设计
@ -602,7 +632,7 @@ XXL-JOB调度模块基于Quartz集群实现其“调度数据库”是在Quar
XXL-JOB首先定制了Quartz原生表结构前缀XXL_JOB_QRTZ_
![输入图片说明](https://static.oschina.net/uploads/img/201607/24143957_bNwm.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_bNwm.png "在这里输入图片标题")
然后,在此基础上新增了几张张扩展表,如下:
- XXL_JOB_QRTZ_TRIGGER_GROUP执行器信息表维护任务执行器信息
@ -631,14 +661,17 @@ XXL-JOB首先定制了Quartz原生表结构前缀XXL_JOB_QRTZ_
#### 5.3.3 架构图
![输入图片说明](https://static.oschina.net/uploads/img/201801/03103007_Qohm.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Qohm.png "在这里输入图片标题")
### 5.4 调度模块剖析
#### 5.4.1 quartz的不足
Quartz作为开源作业调度中的佼佼者是作业调度的首选。但是集群环境中Quartz采用API的方式对任务进行管理从而可以避免上述问题但是同样存在以下问题
- 问题一调用API的的方式操作任务不人性化
- 问题二需要持久化业务QuartzJobBean到底层数据表中系统侵入性相当严重。
- 问题三调度逻辑和QuartzJobBean耦合在同一个项目中这将导致一个问题在调度任务数量逐渐增多同时调度任务逻辑逐渐加重的情况加此时调度系统的性能将大大受限于业务
- 问题一调用API的的方式操作任务不人性化
- 问题二需要持久化业务QuartzJobBean到底层数据表中系统侵入性相当严重。
- 问题三调度逻辑和QuartzJobBean耦合在同一个项目中这将导致一个问题在调度任务数量逐渐增多同时调度任务逻辑逐渐加重的情况加此时调度系统的性能将大大受限于业务
- 问题四quartz底层以“抢占式”获取DB锁并由抢占成功节点负责运行任务会导致节点负载悬殊非常大而XXL-JOB通过执行器实现“协同分配式”运行任务充分发挥集群优势负载各节点均衡。
XXL-JOB弥补了quartz的上述不足之处。
#### 5.4.2 RemoteHttpJobBean
@ -727,7 +760,7 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback
当任务"路由策略"选择"故障转移(FAILOVER)"时,当调度中心每次发起调度请求时,会按照顺序对执行器发出心跳检测请求,第一个检测为存活状态的执行器将会被选定并发送调度请求。
调度成功后,可在日志监控界面查看“调度备注”,如下;
![输入图片说明](https://static.oschina.net/uploads/img/201703/12230733_jrdI.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_jrdI.png "在这里输入图片标题")
“调度备注”可以看出本地调度运行轨迹,执行器的"注册方式"、"地址列表"和任务的"路由策略"。"故障转移(FAILOVER)"路由策略下,调度中心首先对第一个地址进行心跳检测,心跳失败因此自动跳过,第二个依然心跳检测失败……
直至心跳检测第三个地址“127.0.0.1:9999”成功选定为“目标执行器”然后对“目标执行器”发送调度请求调度流程结束等待执行器回调执行结果。
@ -758,9 +791,9 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback
在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。
![输入图片说明](https://static.oschina.net/uploads/img/201607/24194134_Wb2o.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_Wb2o.png "在这里输入图片标题")
![输入图片说明](https://static.oschina.net/uploads/img/201607/24194212_jOAU.png "在这里输入图片标题")
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/img_jOAU.png "在这里输入图片标题")
### 5.5 任务 "运行模式" 剖析
#### 5.5.1 "Bean模式" 任务
@ -773,14 +806,15 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback
#### 5.5.3 GLUE模式(Shell) + GLUE模式(Python) + GLUE模式(NodeJS)
开发步骤:可参考 "章节三"
原理脚本任务的源码托管在调度中心脚本逻辑在执行器运行。当触发脚本任务时执行器会加载脚本源码在执行器机器上生成一份脚本文件然后通过Java代码调用该脚本并且实时将脚本输出日志写到任务日志文件中从而在调度中心可以实时监控脚本运行情况脚本返回码为0时表示执行成功其他标示执行失败。
原理脚本任务的源码托管在调度中心脚本逻辑在执行器运行。当触发脚本任务时执行器会加载脚本源码在执行器机器上生成一份脚本文件然后通过Java代码调用该脚本并且实时将脚本输出日志写到任务日志文件中从而在调度中心可以实时监控脚本运行情况
目前支持的脚本类型如下:
- shell脚本任务运行模式选择为 "GLUE模式(Shell)"时支持 "shell" 脚本任务;
- python脚本任务运行模式选择为 "GLUE模式(Python)"时支持 "python" 脚本任务;
- nodejs脚本务运行模式选择为 "GLUE模式(NodeJS)"时支持 "nodejs" 脚本任务;
脚本任务通过 Exit Code 判断任务执行结果,状态码可参考章节 "5.15 任务执行结果说明"
#### 5.5.4 执行器
执行器实际上是一个内嵌的Jetty服务器默认端口9999配置项xxl.job.executor.port
@ -895,6 +929,25 @@ echo "分片总数 total = $3"
- 调度中心调度失败时,任务失败处理策略选择"失败重试",将会自动重试一次;
- 执行器运行失败时,任务执行结果返回"失败重试IJobHandler.FAIL_RETRY"回调,将会自动重试一次;
### 5.14 执行器灰度上线
调度中心与业务解耦只需部署一次后常年不需要维护。但是执行器中托管运行着业务作业作业上线和变更需要重启执行器尤其是Bean模式任务。
执行器重启可能会中断运行中的任务。但是XXL-JOB得益于自建执行器与自建注册中心可以通过灰度上线的方式避免因重启导致的任务中断的问题。
步骤如下:
- 1、执行器改为手动注册下线一半机器列表A组线上运行另一半机器列表B组
- 2、等待A组机器任务运行结束并编译上线执行器注册地址替换为A组
- 3、等待B组机器任务运行结束并编译上线执行器注册地址替换为A组+B组
操作结束;
### 5.15 任务执行结果说明
系统根据以下标准判断任务执行结果,可参考之。
-- | Bean/Glue(Java) | Glue(Shell) 等脚本任务
--- | --- | ---
成功 | IJobHandler.SUCCESS | 0
失败 | IJobHandler.FAIL | -1其他
失败重试 | IJobHandler.FAIL_RETRY | 101
## 六、版本更新日志
### 6.1 版本 V1.1.x新特性[2015-12-05]
@ -1154,6 +1207,22 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 8、项目依赖全量升级至较新稳定版本如spring、jackson等等
### 6.22 版本 V1.9.2 特性[迭代中]
- 1、[迭代中]支持通过API服务操作任务信息
- 2、[迭代中]任务告警逻辑调整任务调度以及任务回调失败时均推送监控队列。后期考虑通过任务Log字段控制告警状态
- 3、[迭代中]任务超时设置,超时任务主动终止;
- 4、任务属性枚举 "任务模式、阻塞策略" 国际化优化;
- 5、任务日志表状态字段类型优化
- 6、Glue(Shell) 等脚本任务支持失败重试;
- 7、告警邮箱支持SSL配置
- 8、Window机器下File.separator不兼容问题修复
- 9、任务日志查询速度优化百万级别日志量搜索速度提升1000倍
- 10、底层LocalCache组件兼容性优化支持jdk、jdk10编译部署
- 11、任务回调结果优化支持展示在Rolling log中方便问题排查
- 12、脚本任务异常Log输出优化
- 13、任务线程停止变量修饰符优化
- 14、脚本任务Log文件流关闭优化
- 15、任务报表成功、失败和进行中统计问题修复
- 16、自研Log组件参数占位符改为"{}",并修复打印有参日志时参数不匹配导致报错的问题;
### TODO LIST
@ -1165,7 +1234,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 6、调度任务优先级
- 7、移除quartz依赖重写调度模块新增或恢复任务时将下次执行记录插入delayqueue调度中心集群竞争分布式锁成功节点批量加载到期delayqueue数据批量执行。
- 8、springboot 和 docker镜像并且推送docker镜像到中央仓库更进一步实现产品开箱即用
- 9、任务告警逻辑调整任务调度以及任务回调失败时均推送监控队列。后期考虑通过任务Log字段控制告警状态
- 9、多数据库支持
- 10、执行器Log清理功能调度中心Log删除时同步删除执行器中的Log文件
- 11、Bean模式任务JobHandler自动从执行器中查询展示为下拉框选择后自动填充任务名称等属性
- 12、API事件触发类型任务更类似MQ消息支持"动态传参、延时消费"该类型任务不走Quartz单独建立MQ消息表调度中心竞争触发
@ -1175,10 +1244,13 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 16、新增API服务 "XxlJobService" 支持通过API服务来维护管理任务信息
- 17、新增任务默认运行状态任务更新时运行状态保持不变
- 18、告警邮件中展示失败告警信息
- 19、多数据库支持
- 20、提供多版本执行器不依赖容器版本、不内嵌Jetty版本等
- 21、支持通过API服务操作任务信息
- 22、任务超时设置超时任务主动终止
- 19、提供多版本执行器不依赖容器版本、不内嵌Jetty版本通过配置executoraddress替换jetty通讯
- 20、注册中心支持扩展除默认基于DB之外支持扩展接入第三方注册中心如zk、eureka等
- 21、依赖Core内部国际化处理
- 22、故障转移、失败重试等策略规范化合并归类
- 23、流程任务支持参数传递
- 24、SimpleTrigger 支持;
- 25、springboot热部署支持
## 七、其他

View File

@ -181,12 +181,13 @@ CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_LOG` (
`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
`executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
`trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',
`trigger_code` varchar(255) NOT NULL DEFAULT '0' COMMENT '调度-结果',
`trigger_code` int(11) NOT NULL COMMENT '调度-结果',
`trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志',
`handle_time` datetime DEFAULT NULL COMMENT '执行-时间',
`handle_code` varchar(255) NOT NULL DEFAULT '0' COMMENT '执行-状态',
`handle_code` int(11) NOT NULL COMMENT '执行-状态',
`handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志',
PRIMARY KEY (`id`)
PRIMARY KEY (`id`),
KEY `I_trigger_time` (`trigger_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_LOGGLUE` (

BIN
doc/images/img_6yC0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

BIN
doc/images/img_9235.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
doc/images/img_BPLG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

BIN
doc/images/img_EB65.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
doc/images/img_Fgql.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
doc/images/img_Hr2T.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
doc/images/img_Qohm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

BIN
doc/images/img_UDSo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

BIN
doc/images/img_V3vF.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
doc/images/img_Wb2o.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
doc/images/img_Ypik.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

BIN
doc/images/img_Z5wp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
doc/images/img_Z9Qr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
doc/images/img_ZAhX.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
doc/images/img_ZAsz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

BIN
doc/images/img_bNwm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

BIN
doc/images/img_dNUJ.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

BIN
doc/images/img_eYrv.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
doc/images/img_hIci.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
doc/images/img_iUw0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
doc/images/img_inc8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

BIN
doc/images/img_jOAU.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
doc/images/img_jrdI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
doc/images/img_o8HQ.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

BIN
doc/images/img_oLlM.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

BIN
doc/images/img_tJOq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
doc/images/img_tvGI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

View File

@ -27,6 +27,9 @@ public class XxlJobAdminConfig implements InitializingBean{
@Value("${xxl.job.mail.port}")
private String mailPort;
@Value("${xxl.job.mail.ssl}")
private boolean mailSSL;
@Value("${xxl.job.mail.username}")
private String mailUsername;
@ -54,6 +57,10 @@ public class XxlJobAdminConfig implements InitializingBean{
return mailPort;
}
public boolean isMailSSL() {
return mailSSL;
}
public String getMailUsername() {
return mailUsername;
}

View File

@ -4,12 +4,14 @@ import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.thread.JobFailMonitorHelper;
import com.xxl.job.admin.core.thread.JobRegistryMonitorHelper;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.admin.dao.XxlJobRegistryDao;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import com.xxl.job.core.rpc.netcom.NetComServerFactory;
import org.quartz.*;
@ -76,11 +78,20 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware {
NetComServerFactory.putService(AdminBiz.class, XxlJobDynamicScheduler.adminBiz);
NetComServerFactory.setAccessToken(accessToken);
// init i18n
initI18n();
// valid
Assert.notNull(scheduler, "quartz scheduler is null");
logger.info(">>>>>>>>> init xxl-job admin success.");
}
private void initI18n(){
for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {
item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name())));
}
}
public void destroy(){
// admin registry stop
JobRegistryMonitorHelper.getInstance().toStop();

View File

@ -56,22 +56,22 @@ public class JobFailMonitorHelper {
continue;
}
if (IJobHandler.SUCCESS.getCode() == log.getTriggerCode() && log.getHandleCode() == 0) {
// job running
JobFailMonitorHelper.monitor(jobLogId);
logger.info(">>>>>>>>>>> job monitor, job running, JobLogId:{}", jobLogId);
} else if (IJobHandler.SUCCESS.getCode() == log.getHandleCode()) {
// job success, pass
logger.info(">>>>>>>>>>> job monitor, job success, JobLogId:{}", jobLogId);
} else if (IJobHandler.FAIL.getCode() == log.getTriggerCode()
} else /*if (IJobHandler.FAIL.getCode() == log.getTriggerCode()
|| IJobHandler.FAIL.getCode() == log.getHandleCode()
|| IJobHandler.TIMEOUT.getCode() == log.getHandleCode()
|| IJobHandler.FAIL_RETRY.getCode() == log.getHandleCode() ) {
|| IJobHandler.FAIL_RETRY.getCode() == log.getHandleCode() )*/ {
// job fail,
failAlarm(log);
logger.info(">>>>>>>>>>> job monitor, job fail, JobLogId:{}", jobLogId);
} else {
}/* else {
JobFailMonitorHelper.monitor(jobLogId);
logger.info(">>>>>>>>>>> job monitor, job status unknown, JobLogId:{}", jobLogId);
}
}*/
}
}

View File

@ -30,7 +30,7 @@ public class I18nUtil {
return prop;
}
try {
// bild i18n prop
// build i18n prop
String i18n = XxlJobAdminConfig.getAdminConfig().getI18n();
i18n = StringUtils.isNotBlank(i18n)?("_"+i18n):i18n;
String i18nFile = MessageFormat.format("i18n/message{0}.properties", i18n);

View File

@ -3,6 +3,7 @@ package com.xxl.job.admin.core.util;
import org.apache.commons.lang3.StringUtils;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* local cache tool
@ -11,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class LocalCacheUtil {
private static ConcurrentHashMap<String, LocalCacheData> cacheRepository = new ConcurrentHashMap<>();
private static ConcurrentMap<String, LocalCacheData> cacheRepository = new ConcurrentHashMap<String, LocalCacheData>(); // 类型建议用抽象父类兼容性更好
private static class LocalCacheData{
private String key;
private Object val;

View File

@ -35,8 +35,14 @@ public class MailUtil {
//email.setSSL(true);
email.setHostName(XxlJobAdminConfig.getAdminConfig().getMailHost());
email.setSmtpPort(Integer.valueOf(XxlJobAdminConfig.getAdminConfig().getMailPort()));
//email.setSslSmtpPort(port);
if (XxlJobAdminConfig.getAdminConfig().isMailSSL()) {
email.setSslSmtpPort(XxlJobAdminConfig.getAdminConfig().getMailPort());
email.setSSLOnConnect(true);
} else {
email.setSmtpPort(Integer.valueOf(XxlJobAdminConfig.getAdminConfig().getMailPort()));
}
email.setAuthenticator(new DefaultAuthenticator(XxlJobAdminConfig.getAdminConfig().getMailUsername(), XxlJobAdminConfig.getAdminConfig().getMailPassword()));
email.setCharset(Charset.defaultCharset().name());

View File

@ -6,7 +6,6 @@ import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.core.util.LocalCacheUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao;
@ -324,12 +323,12 @@ public class XxlJobServiceImpl implements XxlJobService {
private static final String TRIGGER_CHART_DATA_CACHE = "trigger_chart_data_cache";
@Override
public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
// get cache
/*// get cache
String cacheKey = TRIGGER_CHART_DATA_CACHE + "_" + startDate.getTime() + "_" + endDate.getTime();
Map<String, Object> chartInfo = (Map<String, Object>) LocalCacheUtil.get(cacheKey);
if (chartInfo != null) {
return new ReturnT<Map<String, Object>>(chartInfo);
}
}*/
// process
List<String> triggerDayList = new ArrayList<String>();
@ -376,8 +375,8 @@ public class XxlJobServiceImpl implements XxlJobService {
result.put("triggerCountSucTotal", triggerCountSucTotal);
result.put("triggerCountFailTotal", triggerCountFailTotal);
// set cache
LocalCacheUtil.set(cacheKey, result, 60*1000); // cache 60s
/*// set cache
LocalCacheUtil.set(cacheKey, result, 60*1000); // cache 60s*/
return new ReturnT<Map<String, Object>>(result);
}

View File

@ -193,6 +193,9 @@ jobgroup_del_limit_0=拒绝删除,该执行器使用中
jobgroup_del_limit_1=拒绝删除, 系统至少保留一个执行器
## job conf
jobconf_block_SERIAL_EXECUTION=单机串行
jobconf_block_DISCARD_LATER=丢弃后续调度
jobconf_block_COVER_EARLY=覆盖之前调度
jobconf_fail_alarm=失败告警
jobconf_fail_retry=失败重试
jobconf_route_first=第一个

View File

@ -193,6 +193,9 @@ jobgroup_del_limit_0=Refuse to delete, the executor is being used
jobgroup_del_limit_1=Refuses to delete, the system retains at least one executor
## job conf
jobconf_block_SERIAL_EXECUTION=Serial execution
jobconf_block_DISCARD_LATER=Discard Later
jobconf_block_COVER_EARLY=Cover Early
jobconf_fail_alarm=Fail Alarm
jobconf_fail_retry=Fail Retry
jobconf_route_first=First

View File

@ -45,7 +45,7 @@
SELECT <include refid="Base_Column_List" />
FROM XXL_JOB_QRTZ_TRIGGER_LOG AS t
<trim prefix="WHERE" prefixOverrides="AND | OR" >
<if test="jobGroup != null and jobGroup != ''">
<if test="jobGroup gt 0">
AND t.job_group = #{jobGroup}
</if>
<if test="jobId gt 0">
@ -62,12 +62,13 @@
</if>
<if test="logStatus == 2" >
AND (
(t.trigger_code <![CDATA[ > ]]> 0 AND t.trigger_code!=200) ||
(t.handle_code <![CDATA[ > ]]> 0 AND t.handle_code!=200)
t.trigger_code NOT IN (0, 200) OR
t.handle_code NOT IN (0, 200)
)
</if>
<if test="logStatus == 3" >
AND (t.trigger_code = 200 AND t.handle_code=0)
AND t.trigger_code = 200
AND t.handle_code = 0
</if>
</trim>
ORDER BY id DESC
@ -78,7 +79,7 @@
SELECT count(1)
FROM XXL_JOB_QRTZ_TRIGGER_LOG AS t
<trim prefix="WHERE" prefixOverrides="AND | OR" >
<if test="jobGroup != null and jobGroup != ''">
<if test="jobGroup gt 0">
AND t.job_group = #{jobGroup}
</if>
<if test="jobId gt 0">
@ -95,12 +96,13 @@
</if>
<if test="logStatus == 2" >
AND (
(t.trigger_code <![CDATA[ > ]]> 0 AND t.trigger_code!=200) ||
(t.handle_code <![CDATA[ > ]]> 0 AND t.handle_code!=200)
t.trigger_code NOT IN (0, 200) OR
t.handle_code NOT IN (0, 200)
)
</if>
<if test="logStatus == 3" >
AND (t.trigger_code = 200 AND t.handle_code=0)
AND t.trigger_code = 200
AND t.handle_code = 0
</if>
</trim>
</select>
@ -115,10 +117,14 @@
<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobLog" useGeneratedKeys="true" keyProperty="id" >
INSERT INTO XXL_JOB_QRTZ_TRIGGER_LOG (
`job_group`,
`job_id`
`job_id`,
`trigger_code`,
`handle_code`
) VALUES (
#{jobGroup},
#{jobId}
#{jobId},
#{triggerCode},
#{handleCode}
);
<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
@ -166,7 +172,7 @@
SELECT
DATE_FORMAT(trigger_time,'%Y-%m-%d') triggerDay,
COUNT(handle_code) triggerDayCount,
SUM(CASE WHEN handle_code = 0 then 1 else 0 end) as triggerDayCountRunning,
SUM(CASE WHEN (trigger_code = 200 and handle_code = 0) then 1 else 0 end) as triggerDayCountRunning,
SUM(CASE WHEN handle_code = 200 then 1 else 0 end) as triggerDayCountSuc
FROM XXL_JOB_QRTZ_TRIGGER_LOG
WHERE trigger_time BETWEEN #{from} and #{to}

View File

@ -7,6 +7,7 @@ xxl.job.db.password=root_pwd
### xxl-job email
xxl.job.mail.host=smtp.163.com
xxl.job.mail.port=25
xxl.job.mail.ssl=false
xxl.job.mail.username=ovono802302@163.com
xxl.job.mail.password=asdfzxcv
xxl.job.mail.sendNick=《任务调度平台XXL-JOB》

View File

@ -135,7 +135,7 @@
</#list>
</select>
</div>
<label for="firstname" class="col-sm-2 control-label">JobHandler<font color="black">*</font></label>
<label for="firstname" class="col-sm-2 control-label">JobHandler<font color="red">*</font></label>
<div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
</div>
<div class="form-group">
@ -308,7 +308,7 @@ process.exit(0)
</#list>
</select>
</div>
<label for="firstname" class="col-sm-2 control-label">JobHandler<font color="black">*</font></label>
<label for="firstname" class="col-sm-2 control-label">JobHandler<font color="red">*</font></label>
<div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
</div>
<div class="form-group">

View File

@ -229,7 +229,7 @@ $(function() {
end: function(layero, index){
if (needFresh) {
//window.location.reload();
jobTable.fnDraw();
jobTable.fnDraw(false);
}
}
});

View File

@ -18,7 +18,7 @@ import java.text.MessageFormat;
public class MailUtilTest {
@Test
public void registryTest() throws Exception {
public void mailTest() throws Exception {
String mailBodyTemplate = "<h5>监控告警明细:</span>" +
"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +

View File

@ -13,6 +13,9 @@ public interface AdminBiz {
public static final String MAPPING = "/api";
// ---------------------- callback ----------------------
/**
* callback
*
@ -21,6 +24,9 @@ public interface AdminBiz {
*/
public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList);
// ---------------------- registry ----------------------
/**
* registry
*
@ -38,6 +44,8 @@ public interface AdminBiz {
public ReturnT<String> registryRemove(RegistryParam registryParam);
// ---------------------- job opt ----------------------
/**
* trigger job for once
*

View File

@ -9,11 +9,14 @@ public class HandleCallbackParam implements Serializable {
private static final long serialVersionUID = 42L;
private int logId;
private long logDateTim;
private ReturnT<String> executeResult;
public HandleCallbackParam(){}
public HandleCallbackParam(int logId, ReturnT<String> executeResult) {
public HandleCallbackParam(int logId, long logDateTim, ReturnT<String> executeResult) {
this.logId = logId;
this.logDateTim = logDateTim;
this.executeResult = executeResult;
}
@ -25,6 +28,14 @@ public class HandleCallbackParam implements Serializable {
this.logId = logId;
}
public long getLogDateTim() {
return logDateTim;
}
public void setLogDateTim(long logDateTim) {
this.logDateTim = logDateTim;
}
public ReturnT<String> getExecuteResult() {
return executeResult;
}
@ -37,7 +48,9 @@ public class HandleCallbackParam implements Serializable {
public String toString() {
return "HandleCallbackParam{" +
"logId=" + logId +
", logDateTim=" + logDateTim +
", executeResult=" + executeResult +
'}';
}
}

View File

@ -5,15 +5,19 @@ package com.xxl.job.core.enums;
*/
public enum ExecutorBlockStrategyEnum {
SERIAL_EXECUTION("单机串行"),
SERIAL_EXECUTION("Serial execution"),
/*CONCURRENT_EXECUTION("并行"),*/
DISCARD_LATER("丢弃后续调度"),
COVER_EARLY("覆盖之前调度");
DISCARD_LATER("Discard Later"),
COVER_EARLY("Cover Early");
private final String title;
private String title;
private ExecutorBlockStrategyEnum (String title) {
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}

View File

@ -5,11 +5,11 @@ package com.xxl.job.core.glue;
*/
public enum GlueTypeEnum {
BEAN("BEAN模式", false, null, null),
GLUE_GROOVY("GLUE模式(Java)", false, null, null),
GLUE_SHELL("GLUE模式(Shell)", true, "bash", ".sh"),
GLUE_PYTHON("GLUE模式(Python)", true, "python", ".py"),
GLUE_NODEJS("GLUE模式(Nodejs)", true, "node", ".js");
BEAN("BEAN", false, null, null),
GLUE_GROOVY("GLUE(Java)", false, null, null),
GLUE_SHELL("GLUE(Shell)", true, "bash", ".sh"),
GLUE_PYTHON("GLUE(Python)", true, "python", ".py"),
GLUE_NODEJS("GLUE(Nodejs)", true, "node", ".js");
private String desc;
private boolean isScript;

View File

@ -8,6 +8,8 @@ import com.xxl.job.core.log.XxlJobLogger;
import com.xxl.job.core.util.ScriptUtil;
import com.xxl.job.core.util.ShardingUtil;
import java.io.File;
/**
* Created by xuxueli on 17/4/27.
*/
@ -41,7 +43,7 @@ public class ScriptJobHandler extends IJobHandler {
// make script file
String scriptFileName = XxlJobFileAppender.getGlueSrcPath()
.concat("/")
.concat(File.separator)
.concat(String.valueOf(jobId))
.concat("_")
.concat(String.valueOf(glueUpdatetime))
@ -61,8 +63,15 @@ public class ScriptJobHandler extends IJobHandler {
// invoke
XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------");
int exitValue = ScriptUtil.execToFile(cmd, scriptFileName, logFileName, scriptParams);
ReturnT<String> result = (exitValue==0)?IJobHandler.SUCCESS:new ReturnT<String>(IJobHandler.FAIL.getCode(), "script exit value("+exitValue+") is failed");
return result;
if (exitValue == 0) {
return IJobHandler.SUCCESS;
} else if (exitValue == 101) {
return IJobHandler.FAIL_RETRY;
} else {
return new ReturnT<String>(IJobHandler.FAIL.getCode(), "script exit value("+exitValue+") is failed");
}
}
}

View File

@ -79,7 +79,7 @@ public class XxlJobFileAppender {
// filePath/yyyy-MM-dd/9999.log
String logFileName = logFilePath.getPath()
.concat("/")
.concat(File.separator)
.concat(String.valueOf(logId))
.concat(".log");
return logFileName;
@ -115,23 +115,21 @@ public class XxlJobFileAppender {
appendLog += "\r\n";
// append file content
FileOutputStream fos = null;
try {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(logFile, true);
fos.write(appendLog.getBytes("utf-8"));
fos.flush();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
fos = new FileOutputStream(logFile, true);
fos.write(appendLog.getBytes("utf-8"));
fos.flush();
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
}

View File

@ -2,10 +2,11 @@ package com.xxl.job.core.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@ -49,15 +50,18 @@ public class XxlJobLogger {
/**
* append log with pattern
*
* @param appendLogPattern like "aaa {0} bbb {1} ccc"
* @param appendLogPattern like "aaa {} bbb {} ccc"
* @param appendLogArguments like "111, true"
*/
public static void log(String appendLogPattern, Object ... appendLogArguments) {
String appendLog = appendLogPattern;
FormattingTuple ft = MessageFormatter.format(appendLogPattern, appendLogArguments);
String appendLog = ft.getMessage();
/*appendLog = appendLogPattern;
if (appendLogArguments!=null && appendLogArguments.length>0) {
appendLog = MessageFormat.format(appendLogPattern, appendLogArguments);
}
}*/
StackTraceElement callInfo = new Throwable().getStackTrace()[1];
logDetail(callInfo, appendLog);

View File

@ -58,8 +58,7 @@ public class NetComClientProxy implements FactoryBean<Object> {
// valid response
if (response == null) {
logger.error(">>>>>>>>>>> xxl-rpc netty response not found.");
throw new Exception(">>>>>>>>>>> xxl-rpc netty response not found.");
throw new Exception("Network request fail, response not found.");
}
if (response.isError()) {
throw new RuntimeException(response.getError());

View File

@ -29,7 +29,7 @@ public class JettyClient {
byte[] responseBytes = HttpClientUtil.postRequest(reqURL, requestBytes);
if (responseBytes == null || responseBytes.length==0) {
RpcResponse rpcResponse = new RpcResponse();
rpcResponse.setError("RpcResponse byte[] is null");
rpcResponse.setError("Network request fail, RpcResponse byte[] is null");
return rpcResponse;
}
@ -40,7 +40,7 @@ public class JettyClient {
logger.error(e.getMessage(), e);
RpcResponse rpcResponse = new RpcResponse();
rpcResponse.setError("Client-error:" + e.getMessage());
rpcResponse.setError("Network request error: " + e.getMessage());
return rpcResponse;
}
}

View File

@ -8,16 +8,22 @@ import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.log.XxlJobLogger;
import com.xxl.job.core.util.ShardingUtil;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.*;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* handler thread
* @author xuxueli 2016-1-16 19:52:47
@ -28,9 +34,9 @@ public class JobThread extends Thread{
private int jobId;
private IJobHandler handler;
private LinkedBlockingQueue<TriggerParam> triggerQueue;
private ConcurrentHashSet<Integer> triggerLogIdSet; // avoid repeat trigger for the same TRIGGER_LOG_ID
private Set<Integer> triggerLogIdSet; // avoid repeat trigger for the same TRIGGER_LOG_ID
private boolean toStop = false;
private volatile boolean toStop = false;
private String stopReason;
private boolean running = false; // if running job
@ -41,7 +47,7 @@ public class JobThread extends Thread{
this.jobId = jobId;
this.handler = handler;
this.triggerQueue = new LinkedBlockingQueue<TriggerParam>();
this.triggerLogIdSet = new ConcurrentHashSet<Integer>();
this.triggerLogIdSet = Collections.synchronizedSet(new HashSet<Integer>());
}
public IJobHandler getHandler() {
return handler;
@ -171,11 +177,11 @@ public class JobThread extends Thread{
// callback handler info
if (!toStop) {
// commonm
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), executeResult));
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTim(), executeResult));
} else {
// is killed
ReturnT<String> stopResult = new ReturnT<String>(ReturnT.FAIL_CODE, stopReason + " [业务运行中,被强制终止]");
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), stopResult));
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTim(), stopResult));
}
}
}
@ -187,7 +193,7 @@ public class JobThread extends Thread{
if (triggerParam!=null) {
// is killed
ReturnT<String> stopResult = new ReturnT<String>(ReturnT.FAIL_CODE, stopReason + " [任务尚未执行,在调度队列中被终止]");
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), stopResult));
TriggerCallbackThread.pushCallBack(new HandleCallbackParam(triggerParam.getLogId(), triggerParam.getLogDateTim(), stopResult));
}
}

View File

@ -4,10 +4,13 @@ import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.log.XxlJobLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
@ -108,17 +111,27 @@ public class TriggerCallbackThread {
try {
ReturnT<String> callbackResult = adminBiz.callback(callbackParamList);
if (callbackResult!=null && ReturnT.SUCCESS_CODE == callbackResult.getCode()) {
callbackResult = ReturnT.SUCCESS;
logger.info(">>>>>>>>>>> xxl-job callback success, callbackParamList:{}, callbackResult:{}", new Object[]{callbackParamList, callbackResult});
callbackLog(callbackParamList, "<br>----------- xxl-job callback success");
break;
} else {
logger.info(">>>>>>>>>>> xxl-job callback fail, callbackParamList:{}, callbackResult:{}", new Object[]{callbackParamList, callbackResult});
callbackLog(callbackParamList, "<br>----------- xxl-job callback fail, callbackResult:" + callbackResult);
}
} catch (Exception e) {
logger.error(">>>>>>>>>>> xxl-job callback error, callbackParamList{}", callbackParamList, e);
callbackLog(callbackParamList, "<br>----------- xxl-job callback error, errorMsg:" + e.getMessage());
//getInstance().callBackQueue.addAll(callbackParamList);
}
}
}
/**
* callback log
*/
private void callbackLog(List<HandleCallbackParam> callbackParamList, String logContent){
for (HandleCallbackParam callbackParam: callbackParamList) {
String logFileName = XxlJobFileAppender.makeLogFileName(new Date(callbackParam.getLogDateTim()), callbackParam.getLogId());
XxlJobFileAppender.contextHolder.set(logFileName);
XxlJobLogger.log(logContent);
}
}
}

View File

@ -26,7 +26,7 @@ public class HttpClientUtil {
/**
* post request
*/
public static byte[] postRequest(String reqURL, byte[] date) throws Exception {
public static byte[] postRequest(String reqURL, byte[] data) throws Exception {
byte[] responseBytes = null;
HttpPost httpPost = new HttpPost(reqURL);
@ -53,8 +53,8 @@ public class HttpClientUtil {
httpPost.setConfig(requestConfig);
// data
if (date != null) {
httpPost.setEntity(new ByteArrayEntity(date, ContentType.DEFAULT_BINARY));
if (data != null) {
httpPost.setEntity(new ByteArrayEntity(data, ContentType.DEFAULT_BINARY));
}
// do post
HttpResponse response = httpClient.execute(httpPost);
@ -64,7 +64,6 @@ public class HttpClientUtil {
EntityUtils.consume(entity);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw e;
} finally {
httpPost.releaseConnection();

View File

@ -1,5 +1,6 @@
package com.xxl.job.core.util;
import com.xxl.job.core.log.XxlJobLogger;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;
@ -59,7 +60,10 @@ public class ScriptUtil {
// 标准输出print null if watchdog timeout
// 错误输出logging + 异常 still exists if watchdog timeout
// 标准输入
try (FileOutputStream fileOutputStream = new FileOutputStream(logFile, true)) {
FileOutputStream fileOutputStream = null; //
try {
fileOutputStream = new FileOutputStream(logFile, true);
PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
// command
@ -75,6 +79,18 @@ public class ScriptUtil {
exec.setStreamHandler(streamHandler);
int exitValue = exec.execute(commandline); // exit code: 0=success, 1=error
return exitValue;
} catch (Exception e) {
XxlJobLogger.log(e);
return -1;
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
XxlJobLogger.log(e);
}
}
}
}

View File

@ -84,6 +84,7 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>