浏览代码

任务超时控制:支持设置任务超时时间,任务运行超时的情况下,将会主动中断任务;

xuxueli 7 年前
父节点
当前提交
7687f3fc23

+ 19 - 17
README.md 查看文件

@@ -54,23 +54,25 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
54 54
 - 9、失败处理策略;调度失败时的处理策略,策略包括:失败告警(默认)、失败重试;
55 55
 - 10、失败重试:调度中心调度失败且启用"失败重试"策略时,将会自动重试一次;执行器执行失败且回调失败重试状态时,也将会自动重试一次;
56 56
 - 11、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度;
57
-- 12、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务;
58
-- 13、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
59
-- 14、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。
60
-- 15、任务进度监控:支持实时监控任务进度;
61
-- 16、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志;
62
-- 17、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。
63
-- 18、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS等类型脚本;
64
-- 19、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔;
65
-- 20、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;
66
-- 21、自定义任务参数:支持在线配置调度任务入参,即时生效;
67
-- 22、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞;
68
-- 23、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性;
69
-- 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
70
-- 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
71
-- 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
72
-- 27、全异步:系统底层实现全部异步化,针对密集调度进行流量削峰,理论上支持任意时长任务的运行;
73
-- 28、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
57
+- 12、任务超时控制:支持设置任务超时时间,任务运行超时的情况下,将会主动中断任务;
58
+- 13、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务;
59
+- 14、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
60
+- 15、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。
61
+- 16、任务进度监控:支持实时监控任务进度;
62
+- 17、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志;
63
+- 18、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。
64
+- 19、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS等类型脚本;
65
+- 20、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔;
66
+- 21、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;
67
+- 22、自定义任务参数:支持在线配置调度任务入参,即时生效;
68
+- 23、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞;
69
+- 24、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性;
70
+- 25、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
71
+- 26、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
72
+- 27、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
73
+- 28、全异步:系统底层实现全部异步化,针对密集调度进行流量削峰,理论上支持任意时长任务的运行;
74
+- 29、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
75
+
74 76
 
75 77
 ## Development
76 78
 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……

+ 25 - 18
doc/XXL-JOB官方文档.md 查看文件

@@ -25,23 +25,25 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
25 25
 - 9、失败处理策略;调度失败时的处理策略,策略包括:失败告警(默认)、失败重试;
26 26
 - 10、失败重试:调度中心调度失败且启用"失败重试"策略时,将会自动重试一次;执行器执行失败且回调失败重试状态时,也将会自动重试一次;
27 27
 - 11、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度;
28
-- 12、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务;
29
-- 13、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
30
-- 14、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。
31
-- 15、任务进度监控:支持实时监控任务进度;
32
-- 16、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志;
33
-- 17、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。
34
-- 18、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS等类型脚本;
35
-- 19、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔;
36
-- 20、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;
37
-- 21、自定义任务参数:支持在线配置调度任务入参,即时生效;
38
-- 22、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞;
39
-- 23、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性;
40
-- 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
41
-- 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
42
-- 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
43
-- 27、全异步:系统底层实现全部异步化,针对密集调度进行流量削峰,理论上支持任意时长任务的运行;
44
-- 28、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
28
+- 12、任务超时控制:支持设置任务超时时间,任务运行超时的情况下,将会主动中断任务;
29
+- 13、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务;
30
+- 14、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
31
+- 15、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。
32
+- 16、任务进度监控:支持实时监控任务进度;
33
+- 17、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志;
34
+- 18、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。
35
+- 19、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS等类型脚本;
36
+- 20、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔;
37
+- 21、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;
38
+- 22、自定义任务参数:支持在线配置调度任务入参,即时生效;
39
+- 23、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞;
40
+- 24、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性;
41
+- 25、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
42
+- 26、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
43
+- 27、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
44
+- 28、全异步:系统底层实现全部异步化,针对密集调度进行流量削峰,理论上支持任意时长任务的运行;
45
+- 29、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
46
+
45 47
 
46 48
 ### 1.3 发展
47 49
 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
@@ -948,6 +950,11 @@ echo "分片总数 total = $3"
948 950
 失败 | IJobHandler.FAIL | -1(其他)
949 951
 失败重试 | IJobHandler.FAIL_RETRY | 101
950 952
 
953
+### 5.16 任务超时控制
954
+支持设置任务超时时间,任务运行超时的情况下,将会主动中断任务;
955
+
956
+需要注意的是,任务超时中断时与任务终止机制(可查看“4.8 终止运行中的任务”)类似,也是通过 "interrupt" 中断任务,因此业务代码需要将 "InterruptedException" 外抛,否则功能不可用。
957
+
951 958
 
952 959
 ## 六、版本更新日志
953 960
 ### 6.1 版本 V1.1.x,新特性[2015-12-05]
@@ -1209,7 +1216,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
1209 1216
 ### 6.22 版本 V1.9.2 特性[迭代中]
1210 1217
 - 1、[迭代中]支持通过API服务操作任务信息;
1211 1218
 - 2、[迭代中]任务告警逻辑调整:任务调度,以及任务回调失败时,均推送监控队列。后期考虑通过任务Log字段控制告警状态;
1212
-- 3、[迭代中]任务超时设置,超时任务主动终止
1219
+- 3、任务超时控制:支持设置任务超时时间,任务运行超时的情况下,将会主动中断任务
1213 1220
 - 4、任务属性枚举 "任务模式、阻塞策略" 国际化优化;
1214 1221
 - 5、任务日志表状态字段类型优化;
1215 1222
 - 6、Glue(Shell) 等脚本任务支持失败重试;

+ 1 - 1
doc/db/tables_xxl_job.sql 查看文件

@@ -158,12 +158,12 @@ CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_INFO` (
158 158
   `update_time` datetime DEFAULT NULL,
159 159
   `author` varchar(64) DEFAULT NULL COMMENT '作者',
160 160
   `alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
161
-  `execute_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间',
162 161
   `executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略',
163 162
   `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
164 163
   `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
165 164
   `executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略',
166 165
   `executor_fail_strategy` varchar(50) DEFAULT NULL COMMENT '失败处理策略',
166
+  `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒',
167 167
   `glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型',
168 168
   `glue_source` text COMMENT 'GLUE源代码',
169 169
   `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注',

+ 17 - 17
xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java 查看文件

@@ -4,6 +4,7 @@ import java.util.Date;
4 4
 
5 5
 /**
6 6
  * xxl-job info
7
+ *
7 8
  * @author xuxueli  2016-1-12 18:25:49
8 9
  */
9 10
 public class XxlJobInfo {
@@ -25,6 +26,7 @@ public class XxlJobInfo {
25 26
 	private String executorParam;		    // 执行器,任务参数
26 27
 	private String executorBlockStrategy;	// 阻塞处理策略
27 28
 	private String executorFailStrategy;	// 失败处理策略
29
+	private int executorTimeout;     		// 任务执行超时时间,单位秒
28 30
 	
29 31
 	private String glueType;		// GLUE类型	#com.xxl.job.core.glue.GlueTypeEnum
30 32
 	private String glueSource;		// GLUE源代码
@@ -36,16 +38,6 @@ public class XxlJobInfo {
36 38
 	// copy from quartz
37 39
 	private String jobStatus;		// 任务状态 【base on quartz】
38 40
 
39
-	private int executeTimeout;     // 任务最多执行时间,超时后报警
40
-
41
-	public int getExecuteTimeout() {
42
-		return executeTimeout;
43
-	}
44
-
45
-	public void setExecuteTimeout(int executeTimeout) {
46
-		this.executeTimeout = executeTimeout;
47
-	}
48
-
49 41
 
50 42
 	public int getId() {
51 43
 		return id;
@@ -111,15 +103,15 @@ public class XxlJobInfo {
111 103
 		this.alarmEmail = alarmEmail;
112 104
 	}
113 105
 
114
-    public String getExecutorRouteStrategy() {
115
-        return executorRouteStrategy;
116
-    }
106
+	public String getExecutorRouteStrategy() {
107
+		return executorRouteStrategy;
108
+	}
117 109
 
118
-    public void setExecutorRouteStrategy(String executorRouteStrategy) {
119
-        this.executorRouteStrategy = executorRouteStrategy;
120
-    }
110
+	public void setExecutorRouteStrategy(String executorRouteStrategy) {
111
+		this.executorRouteStrategy = executorRouteStrategy;
112
+	}
121 113
 
122
-    public String getExecutorHandler() {
114
+	public String getExecutorHandler() {
123 115
 		return executorHandler;
124 116
 	}
125 117
 
@@ -151,6 +143,14 @@ public class XxlJobInfo {
151 143
 		this.executorFailStrategy = executorFailStrategy;
152 144
 	}
153 145
 
146
+	public int getExecutorTimeout() {
147
+		return executorTimeout;
148
+	}
149
+
150
+	public void setExecutorTimeout(int executorTimeout) {
151
+		this.executorTimeout = executorTimeout;
152
+	}
153
+
154 154
 	public String getGlueType() {
155 155
 		return glueType;
156 156
 	}

+ 4 - 3
xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java 查看文件

@@ -75,6 +75,7 @@ public class XxlJobTrigger {
75 75
                 triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01
76 76
                 triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle());
77 77
                 triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailStrategy")).append(":").append(failStrategy.getTitle());
78
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_timeout")).append(":").append(jobInfo.getExecutorTimeout());
78 79
 
79 80
                 // 3、trigger-valid
80 81
                 if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
@@ -89,6 +90,7 @@ public class XxlJobTrigger {
89 90
                     triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
90 91
                     triggerParam.setExecutorParams(jobInfo.getExecutorParam());
91 92
                     triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
93
+                    triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout());
92 94
                     triggerParam.setLogId(jobLog.getId());
93 95
                     triggerParam.setLogDateTim(jobLog.getTriggerTime().getTime());
94 96
                     triggerParam.setGlueType(jobInfo.getGlueType());
@@ -96,8 +98,6 @@ public class XxlJobTrigger {
96 98
                     triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
97 99
                     triggerParam.setBroadcastIndex(i);
98 100
                     triggerParam.setBroadcastTotal(addressList.size()); // update02
99
-                    // 执行超时时间
100
-                    triggerParam.setExecuteTimeout(jobInfo.getExecuteTimeout());
101 101
 
102 102
                     // 4.2、trigger-run (route run / trigger remote executor)
103 103
                     triggerResult = runExecutor(triggerParam, address);     // update03
@@ -145,6 +145,7 @@ public class XxlJobTrigger {
145 145
             triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle());
146 146
             triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle());
147 147
             triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailStrategy")).append(":").append(failStrategy.getTitle());
148
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_timeout")).append(":").append(jobInfo.getExecutorTimeout());
148 149
 
149 150
             // 3、trigger-valid
150 151
             if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
@@ -159,6 +160,7 @@ public class XxlJobTrigger {
159 160
                 triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
160 161
                 triggerParam.setExecutorParams(jobInfo.getExecutorParam());
161 162
                 triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
163
+                triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout());
162 164
                 triggerParam.setLogId(jobLog.getId());
163 165
                 triggerParam.setLogDateTim(jobLog.getTriggerTime().getTime());
164 166
                 triggerParam.setGlueType(jobInfo.getGlueType());
@@ -166,7 +168,6 @@ public class XxlJobTrigger {
166 168
                 triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
167 169
                 triggerParam.setBroadcastIndex(0);
168 170
                 triggerParam.setBroadcastTotal(1);
169
-                triggerParam.setExecuteTimeout(jobInfo.getExecuteTimeout());
170 171
 
171 172
                 // 4.2、trigger-run (route run / trigger remote executor)
172 173
                 triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);

+ 1 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java 查看文件

@@ -208,6 +208,7 @@ public class XxlJobServiceImpl implements XxlJobService {
208 208
 		exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());
209 209
 		exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
210 210
 		exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy());
211
+		exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());
211 212
 		exists_jobInfo.setChildJobId(jobInfo.getChildJobId());
212 213
         xxlJobInfoDao.update(exists_jobInfo);
213 214
 

+ 3 - 2
xxl-job-admin/src/main/resources/i18n/message.properties 查看文件

@@ -30,6 +30,7 @@ system_opt_del=删除
30 30
 system_unvalid=非法
31 31
 system_not_found=不存在
32 32
 system_nav=导航
33
+system_digits=整数
33 34
 
34 35
 ## daterangepicker
35 36
 daterangepicker_ranges_recent_hour=最近一小时
@@ -107,7 +108,7 @@ jobinfo_field_gluetype=运行模式
107 108
 jobinfo_field_executorparam=任务参数
108 109
 jobinfo_field_cron_unvalid=Cron格式非法
109 110
 jobinfo_field_author=负责人
110
-jobinfo_field_timeout=最大执行时间
111
+jobinfo_field_timeout=任务超时时间
111 112
 jobinfo_field_alarmemail=报警邮件
112 113
 jobinfo_field_alarmemail_placeholder=请输入报警邮件,多个邮件地址则逗号分隔
113 114
 jobinfo_field_executorRouteStrategy=路由策略
@@ -158,7 +159,7 @@ joblog_clean_type_9=清理所有日志数据
158 159
 joblog_clean_type_unvalid=清理类型参数异常
159 160
 joblog_handleCode_200=成功
160 161
 joblog_handleCode_500=失败
161
-joblog_handleCode_400=超时
162
+joblog_handleCode_502=超时
162 163
 joblog_handleCode_501=失败重试
163 164
 joblog_kill_log=终止任务
164 165
 joblog_kill_log_limit=调度失败,无法终止日志

+ 3 - 2
xxl-job-admin/src/main/resources/i18n/message_en.properties 查看文件

@@ -30,6 +30,7 @@ system_opt_del=Delete
30 30
 system_unvalid=illegal
31 31
 system_not_found=not exist
32 32
 system_nav=Navigation
33
+system_digits=digits
33 34
 
34 35
 ## daterangepicker
35 36
 daterangepicker_ranges_recent_hour=recent one hour
@@ -103,7 +104,7 @@ jobinfo_field_update=Edit Job
103 104
 jobinfo_field_id=Job ID
104 105
 jobinfo_field_jobgroup=Executor
105 106
 jobinfo_field_jobdesc=Job description
106
-jobinfo_field_timeout=Max execute time
107
+jobinfo_field_timeout=Job timeout period
107 108
 jobinfo_field_gluetype=GLUE Type
108 109
 jobinfo_field_executorparam=Param
109 110
 jobinfo_field_cron_unvalid=The Cron is illegal
@@ -158,7 +159,7 @@ joblog_clean_type_9=Clean up all log data
158 159
 joblog_clean_type_unvalid=Clean type is illegal
159 160
 joblog_handleCode_200=Success
160 161
 joblog_handleCode_500=Fail
161
-joblog_handleCode_400=Timeout
162
+joblog_handleCode_502=Timeout
162 163
 joblog_handleCode_501=Fail retry
163 164
 joblog_kill_log=Kill Job
164 165
 joblog_kill_log_limit=Trigger Fail, can not kill job

+ 8 - 8
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml 查看文件

@@ -21,12 +21,12 @@
21 21
 	    <result column="executor_param" property="executorParam" />
22 22
 		<result column="executor_block_strategy" property="executorBlockStrategy" />
23 23
 		<result column="executor_fail_strategy" property="executorFailStrategy" />
24
+		<result column="executor_timeout" property="executorTimeout" />
24 25
 
25 26
 	    <result column="glue_type" property="glueType" />
26 27
 	    <result column="glue_source" property="glueSource" />
27 28
 	    <result column="glue_remark" property="glueRemark" />
28 29
 		<result column="glue_updatetime" property="glueUpdatetime" />
29
-		<result column="execute_timeout" property="executeTimeout" />
30 30
 
31 31
 		<result column="child_jobid" property="childJobId" />
32 32
 	</resultMap>
@@ -45,11 +45,11 @@
45 45
 		t.executor_param,
46 46
 		t.executor_block_strategy,
47 47
 		t.executor_fail_strategy,
48
+		t.executor_timeout,
48 49
 		t.glue_type,
49 50
 		t.glue_source,
50 51
 		t.glue_remark,
51 52
 		t.glue_updatetime,
52
-		t.execute_timeout,
53 53
 		t.child_jobid
54 54
 	</sql>
55 55
 
@@ -101,12 +101,12 @@
101 101
 			executor_param,
102 102
 			executor_block_strategy,
103 103
 			executor_fail_strategy,
104
+			executor_timeout,
104 105
 			glue_type,
105 106
 			glue_source,
106 107
 			glue_remark,
107 108
 			glue_updatetime,
108
-			child_jobid,
109
-		    execute_timeout
109
+			child_jobid
110 110
 		) VALUES (
111 111
 			#{jobGroup},
112 112
 			#{jobCron},
@@ -120,12 +120,12 @@
120 120
 			#{executorParam},
121 121
 			#{executorBlockStrategy},
122 122
 			#{executorFailStrategy},
123
+			#{executorTimeout},
123 124
 			#{glueType},
124 125
 			#{glueSource},
125 126
 			#{glueRemark},
126 127
 			NOW(),
127
-			#{childJobId},
128
-		    #{executeTimeout}
128
+			#{childJobId}
129 129
 		);
130 130
 		<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
131 131
 			SELECT LAST_INSERT_ID()
@@ -152,12 +152,12 @@
152 152
 			executor_param = #{executorParam},
153 153
 			executor_block_strategy = #{executorBlockStrategy},
154 154
 			executor_fail_strategy = #{executorFailStrategy},
155
+			executor_timeout = ${executorTimeout},
155 156
 			glue_type = #{glueType},
156 157
 			glue_source = #{glueSource},
157 158
 			glue_remark = #{glueRemark},
158 159
 			glue_updatetime = #{glueUpdatetime},
159
-			child_jobid = #{childJobId},
160
-			execute_timeout = ${executeTimeout}
160
+			child_jobid = #{childJobId}
161 161
 		WHERE id = #{id}
162 162
 	</update>
163 163
 

+ 7 - 2
xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl 查看文件

@@ -170,8 +170,8 @@
170 170
 					</div>
171 171
 
172 172
 					<div class="form-group">
173
-						<label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font color="red">*</font></label>
174
-						<div class="col-sm-4"><input type="text" class="form-control" name="executeTimeout" placeholder="0" maxlength="100" ></div>
173
+						<label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font color="black">*</font></label>
174
+						<div class="col-sm-4"><input type="text" class="form-control" name="executorTimeout" placeholder="任务超时时间,单位秒,大于零时生效" maxlength="6" ></div>
175 175
 					</div>
176 176
 
177 177
                     <hr>
@@ -342,6 +342,11 @@ process.exit(0)
342 342
                         <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></div>
343 343
                     </div>
344 344
 
345
+                    <div class="form-group">
346
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font color="black">*</font></label>
347
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorTimeout" placeholder="任务超时时间,单位秒,大于零时生效" maxlength="6" ></div>
348
+                    </div>
349
+
345 350
 					<hr>
346 351
 					<div class="form-group">
347 352
                         <div class="col-sm-offset-3 col-sm-6">

+ 29 - 4
xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js 查看文件

@@ -264,7 +264,10 @@ $(function() {
264 264
             },
265 265
 			author : {
266 266
 				required : true
267
-			}
267
+			},
268
+            executorTimeout : {
269
+                digits:true
270
+            }
268 271
         }, 
269 272
         messages : {  
270 273
             jobDesc : {
@@ -288,6 +291,14 @@ $(function() {
288 291
             element.parent('div').append(error);  
289 292
         },
290 293
         submitHandler : function(form) {
294
+
295
+			// process
296
+            var executorTimeout = $("#addModal .form input[name='executorTimeout']").val();
297
+            if(!/^\d+$/.test(executorTimeout)) {
298
+                executorTimeout = 0;
299
+			}
300
+            $("#addModal .form input[name='executorTimeout']").val(executorTimeout);
301
+
291 302
         	$.post(base_url + "/jobinfo/add",  $("#addModal .form").serialize(), function(data, status) {
292 303
     			if (data.code == "200") {
293 304
 					$('#addModal').modal('hide');
@@ -362,7 +373,7 @@ $(function() {
362 373
 		$("#updateModal .form input[name='jobCron']").val( row.jobCron );
363 374
 		$("#updateModal .form input[name='author']").val( row.author );
364 375
 		$("#updateModal .form input[name='alarmEmail']").val( row.alarmEmail );
365
-		$("#updateModal .form input[name='executeTimeout']").val( row.executeTimeout );
376
+		$("#updateModal .form input[name='executorTimeout']").val( row.executorTimeout );
366 377
 		$('#updateModal .form select[name=executorRouteStrategy] option[value='+ row.executorRouteStrategy +']').prop('selected', true);
367 378
 		$("#updateModal .form input[name='executorHandler']").val( row.executorHandler );
368 379
 		$("#updateModal .form input[name='executorParam']").val( row.executorParam );
@@ -391,7 +402,10 @@ $(function() {
391 402
 			},
392 403
 			author : {
393 404
 				required : true
394
-			}
405
+			},
406
+            executorTimeout : {
407
+                digits:true
408
+            }
395 409
 		},
396 410
 		messages : {
397 411
 			jobDesc : {
@@ -402,7 +416,10 @@ $(function() {
402 416
 			},
403 417
 			author : {
404 418
 				required : I18n.system_please_input + I18n.jobinfo_field_author
405
-			}
419
+			},
420
+            executorTimeout : {
421
+                digits: I18n.system_please_input + I18n.system_digits
422
+            }
406 423
 		},
407 424
 		highlight : function(element) {
408 425
             $(element).closest('.form-group').addClass('has-error');  
@@ -415,6 +432,14 @@ $(function() {
415 432
             element.parent('div').append(error);  
416 433
         },
417 434
         submitHandler : function(form) {
435
+
436
+            // process
437
+            var executorTimeout = $("#updateModal .form input[name='executorTimeout']").val();
438
+            if(!/^\d+$/.test(executorTimeout)) {
439
+                executorTimeout = 0;
440
+            }
441
+            $("#updateModal .form input[name='executorTimeout']").val(executorTimeout);
442
+
418 443
 			// post
419 444
     		$.post(base_url + "/jobinfo/update", $("#updateModal .form").serialize(), function(data, status) {
420 445
     			if (data.code == "200") {

+ 2 - 2
xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js 查看文件

@@ -159,8 +159,8 @@ $(function() {
159 159
                                 html = '<span style="color: red">'+ I18n.joblog_handleCode_500 +'</span>';
160 160
                             } else if (data == 501) {
161 161
                                 html = '<span style="color: red">'+ I18n.joblog_handleCode_501 +'</span>';
162
-                            } else if (data == 400) {
163
-                                html = '<span style="color: red">'+ I18n.joblog_handleCode_400 +'</span>';
162
+                            } else if (data == 502) {
163
+                                html = '<span style="color: red">'+ I18n.joblog_handleCode_502 +'</span>';
164 164
                             } else if (data == 0) {
165 165
                                 html = '';
166 166
                             }

+ 1 - 3
xxl-job-core/src/main/java/com/xxl/job/core/biz/model/ReturnT.java 查看文件

@@ -12,12 +12,10 @@ public class ReturnT<T> implements Serializable {
12 12
 
13 13
 	public static final int SUCCESS_CODE = 200;
14 14
 	public static final int FAIL_CODE = 500;
15
-	public static final int EXECUTE_TIMEOUT = 400;
16 15
 
17 16
 	public static final ReturnT<String> SUCCESS = new ReturnT<String>(null);
18 17
 	public static final ReturnT<String> FAIL = new ReturnT<String>(FAIL_CODE, null);
19
-	public static final ReturnT<String> TIMEOUT = new ReturnT<String>(EXECUTE_TIMEOUT, "执行超时");
20
-	
18
+
21 19
 	private int code;
22 20
 	private String msg;
23 21
 	private T content;

+ 11 - 9
xxl-job-core/src/main/java/com/xxl/job/core/biz/model/TriggerParam.java 查看文件

@@ -13,6 +13,7 @@ public class TriggerParam implements Serializable{
13 13
     private String executorHandler;
14 14
     private String executorParams;
15 15
     private String executorBlockStrategy;
16
+    private int executorTimeout;
16 17
 
17 18
     private int logId;
18 19
     private long logDateTim;
@@ -24,15 +25,6 @@ public class TriggerParam implements Serializable{
24 25
     private int broadcastIndex;
25 26
     private int broadcastTotal;
26 27
 
27
-    private int executeTimeout;
28
-
29
-    public int getExecuteTimeout() {
30
-        return executeTimeout;
31
-    }
32
-
33
-    public void setExecuteTimeout(int executeTimeout) {
34
-        this.executeTimeout = executeTimeout;
35
-    }
36 28
 
37 29
     public int getJobId() {
38 30
         return jobId;
@@ -66,6 +58,14 @@ public class TriggerParam implements Serializable{
66 58
         this.executorBlockStrategy = executorBlockStrategy;
67 59
     }
68 60
 
61
+    public int getExecutorTimeout() {
62
+        return executorTimeout;
63
+    }
64
+
65
+    public void setExecutorTimeout(int executorTimeout) {
66
+        this.executorTimeout = executorTimeout;
67
+    }
68
+
69 69
     public int getLogId() {
70 70
         return logId;
71 71
     }
@@ -122,6 +122,7 @@ public class TriggerParam implements Serializable{
122 122
         this.broadcastTotal = broadcastTotal;
123 123
     }
124 124
 
125
+
125 126
     @Override
126 127
     public String toString() {
127 128
         return "TriggerParam{" +
@@ -129,6 +130,7 @@ public class TriggerParam implements Serializable{
129 130
                 ", executorHandler='" + executorHandler + '\'' +
130 131
                 ", executorParams='" + executorParams + '\'' +
131 132
                 ", executorBlockStrategy='" + executorBlockStrategy + '\'' +
133
+                ", executorTimeout=" + executorTimeout +
132 134
                 ", logId=" + logId +
133 135
                 ", logDateTim=" + logDateTim +
134 136
                 ", glueType='" + glueType + '\'' +

+ 2 - 2
xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java 查看文件

@@ -14,10 +14,10 @@ public abstract class IJobHandler {
14 14
 	public static final ReturnT<String> SUCCESS = new ReturnT<String>(200, null);
15 15
 	/** fail */
16 16
 	public static final ReturnT<String> FAIL = new ReturnT<String>(500, null);
17
-	/** timeout */
18
-	public static final ReturnT<String> TIMEOUT = new ReturnT<String>(400, null);
19 17
 	/** fail retry */
20 18
 	public static final ReturnT<String> FAIL_RETRY = new ReturnT<String>(501, null);
19
+	/** fail timeout */
20
+	public static final ReturnT<String> FAIL_TIMEOUT = new ReturnT<String>(502, null);
21 21
 
22 22
 
23 23
 	/**

+ 28 - 27
xxl-job-core/src/main/java/com/xxl/job/core/thread/JobThread.java 查看文件

@@ -15,13 +15,9 @@ import java.io.PrintWriter;
15 15
 import java.io.StringWriter;
16 16
 import java.util.Collections;
17 17
 import java.util.Date;
18
-
19
-import java.util.concurrent.*;
20
-
21 18
 import java.util.HashSet;
22 19
 import java.util.Set;
23
-import java.util.concurrent.LinkedBlockingQueue;
24
-import java.util.concurrent.TimeUnit;
20
+import java.util.concurrent.*;
25 21
 
26 22
 
27 23
 /**
@@ -111,7 +107,6 @@ public class JobThread extends Thread{
111 107
 
112 108
             TriggerParam triggerParam = null;
113 109
             ReturnT<String> executeResult = null;
114
-			ExecutorService singleThread = Executors.newSingleThreadExecutor();
115 110
             try {
116 111
 				// to check toStop signal, we need cycle, so wo cannot use queue.take(), instand of poll(timeout)
117 112
 				triggerParam = triggerQueue.poll(3L, TimeUnit.SECONDS);
@@ -127,27 +122,36 @@ public class JobThread extends Thread{
127 122
 
128 123
 					// execute
129 124
 					XxlJobLogger.log("<br>----------- xxl-job job execute start -----------<br>----------- Param:" + triggerParam.getExecutorParams());
130
-					int executeTimeout = triggerParam.getExecuteTimeout();
131
-
132 125
 
133
-					final TriggerParam finalTriggerParam = triggerParam;
134
-
135
-					Future<ReturnT<String>> future = singleThread.submit(new Callable<ReturnT<String>>() {
136
-						@Override
137
-						public ReturnT<String> call() throws Exception {
138
-							return handler.execute(finalTriggerParam.getExecutorParams());
139
-						}
140
-					});
141
-
142
-					try {
143
-						if (executeTimeout > 0) {
144
-							executeResult = future.get(executeTimeout, TimeUnit.SECONDS);
145
-						} else {
146
-							executeResult = future.get();
126
+					if (triggerParam.getExecutorTimeout() > 0) {
127
+						// limit timeout
128
+						Thread futureThread = null;
129
+						try {
130
+							final TriggerParam triggerParamTmp = triggerParam;
131
+							FutureTask<ReturnT<String>> futureTask = new FutureTask<ReturnT<String>>(new Callable<ReturnT<String>>() {
132
+								@Override
133
+								public ReturnT<String> call() throws Exception {
134
+									return handler.execute(triggerParamTmp.getExecutorParams());
135
+								}
136
+							});
137
+							futureThread = new Thread(futureTask);
138
+							futureThread.start();
139
+
140
+							executeResult = futureTask.get(triggerParam.getExecutorTimeout(), TimeUnit.SECONDS);
141
+						} catch (TimeoutException e) {
142
+
143
+							XxlJobLogger.log("<br>----------- xxl-job job execute timeout");
144
+							XxlJobLogger.log(e);
145
+
146
+							executeResult = new ReturnT<String>(IJobHandler.FAIL_TIMEOUT.getCode(), "job execute timeout " + e.getMessage());
147
+						} finally {
148
+							futureThread.interrupt();
147 149
 						}
148
-					} catch (TimeoutException timeoutException) {
149
-						executeResult = ReturnT.TIMEOUT;
150
+					} else {
151
+						// just execute
152
+						executeResult = handler.execute(triggerParam.getExecutorParams());
150 153
 					}
154
+
151 155
 					if (executeResult == null) {
152 156
 						executeResult = IJobHandler.FAIL;
153 157
 					}
@@ -170,9 +174,6 @@ public class JobThread extends Thread{
170 174
 
171 175
 				XxlJobLogger.log("<br>----------- JobThread Exception:" + errorMsg + "<br>----------- xxl-job job execute end(error) -----------");
172 176
 			} finally {
173
-            	if (singleThread != null) {
174
-            		singleThread.shutdown();
175
-				}
176 177
                 if(triggerParam != null) {
177 178
                     // callback handler info
178 179
                     if (!toStop) {