Skip to content

Commit feddec9

Browse files
committed
Merge pull request #45 from qq254963746/develop
LTS Admin: 等待执行队列 编辑和删除
2 parents 3479189 + 24745ef commit feddec9

File tree

10 files changed

+267
-19
lines changed

10 files changed

+267
-19
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ LTS 轻量级分布式任务调度框架(Light Task Scheduler)
22
-----------------
33

44
###框架概况:
5-
LTS是一个轻量级分布式任务调度框架,参考hadoop的部分思想。有三种角色, JobClient, JobTracker, TaskTracker。各个节点都是无状态的,可以部署多个,来实现负载均衡,实现更大的负载量, 并且框架具有很好的容错能力。
5+
LTS是一个轻量级分布式任务调度框架。有三种角色, JobClient, JobTracker, TaskTracker。各个节点都是无状态的,可以部署多个,来实现负载均衡,实现更大的负载量, 并且框架具有很好的容错能力。
66
采用多种注册中心(Zookeeper,redis等)进行节点信息暴露,master选举。(Mongo or Mysql)存储任务队列和任务执行日志, netty做底层通信。
77
* JobClient : 主要负责提交任务, 和 接收任务执行反馈结果。
88
* JobTracker : 负责接收并分配任务,任务调度。

lts-admin/src/main/java/com/lts/web/controller/api/JobQueueApiController.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,46 @@ public RestfulResponse cronJobUpdate(JobQueueRequest request) {
7777
return response;
7878
}
7979
}
80+
try {
81+
Assert.hasLength(request.getJobId(), "jobId不能为空!");
82+
} catch (IllegalArgumentException e) {
83+
response.setSuccess(false);
84+
response.setMsg(e.getMessage());
85+
return response;
86+
}
87+
88+
application.getCronJobQueue().selectiveUpdate(request);
89+
response.setSuccess(true);
90+
return response;
91+
}
92+
93+
@RequestMapping("/job-queue/executable-job-update")
94+
public RestfulResponse executableJobUpdate(JobQueueRequest request) {
95+
RestfulResponse response = new RestfulResponse();
96+
// 检查参数
97+
// 1. 检测 cronExpression是否是正确的
98+
if (StringUtils.isNotEmpty(request.getCronExpression())) {
99+
try {
100+
CronExpression expression = new CronExpression(request.getCronExpression());
101+
if (expression.getTimeAfter(new Date()) == null) {
102+
response.setSuccess(false);
103+
response.setMsg(StringUtils.format("该CronExpression={} 已经没有执行时间点!", request.getCronExpression()));
104+
return response;
105+
}
106+
} catch (ParseException e) {
107+
response.setSuccess(false);
108+
response.setMsg("请输入正确的 CronExpression!");
109+
return response;
110+
}
111+
}
112+
try {
113+
Assert.hasLength(request.getJobId(), "jobId不能为空!");
114+
Assert.hasLength(request.getTaskTrackerNodeGroup(), "taskTrackerNodeGroup不能为空!");
115+
} catch (IllegalArgumentException e) {
116+
response.setSuccess(false);
117+
response.setMsg(e.getMessage());
118+
return response;
119+
}
80120
application.getCronJobQueue().selectiveUpdate(request);
81121
response.setSuccess(true);
82122
return response;
@@ -95,6 +135,23 @@ public RestfulResponse cronJobDelete(JobQueueRequest request) {
95135
return response;
96136
}
97137

138+
@RequestMapping("/job-queue/executable-job-delete")
139+
public RestfulResponse executableJobDelete(JobQueueRequest request) {
140+
RestfulResponse response = new RestfulResponse();
141+
try {
142+
Assert.hasLength(request.getJobId(), "jobId不能为空!");
143+
Assert.hasLength(request.getTaskTrackerNodeGroup(), "taskTrackerNodeGroup不能为空!");
144+
} catch (IllegalArgumentException e) {
145+
response.setSuccess(false);
146+
response.setMsg(e.getMessage());
147+
return response;
148+
}
149+
150+
application.getExecutableJobQueue().remove(request.getTaskTrackerNodeGroup(), request.getJobId());
151+
response.setSuccess(true);
152+
return response;
153+
}
154+
98155
@RequestMapping("/job-logger/job-logger-get")
99156
public RestfulResponse jobLoggerGet(JobLoggerRequest request) {
100157
RestfulResponse response = new RestfulResponse();

lts-admin/src/main/webapp/assets/js/common/date-util.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,23 @@
4040
},
4141

4242
formatYMD: function (date) {
43+
if (!date) {
44+
return date;
45+
}
4346
return this.format(date, this.FORMAT_YMD);
4447
},
4548

4649
formatYMDHMD: function (date) {
50+
if (!date) {
51+
return date;
52+
}
4753
return this.format(date, this.FORMAT_YMD_HMS);
4854
},
4955

5056
formatMD: function (date) {
57+
if(!data){
58+
return date;
59+
}
5160
return this.format(date, 'MM-dd');
5261
},
5362

@@ -341,7 +350,7 @@
341350

342351
// RequireJS && SeaJS
343352
if (typeof define === 'function') {
344-
define(function() {
353+
define(function () {
345354
return DateUtil;
346355
});
347356

lts-admin/src/main/webapp/main/cron-job-queue.jsp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
function buiInit(BUI, Grid, Form, Data, Overlay, DateUtil) {
136136
137137
var columns = [
138-
{title: '任务ID(TaskId)', dataIndex: 'taskId', width: 230, sortable: false},
138+
{title: '任务ID(TaskId)', dataIndex: 'taskId', width: 240, sortable: false},
139139
{title: '提交节点组', dataIndex: 'submitNodeGroup', width: 150},
140140
{title: '执行节点组', dataIndex: 'taskTrackerNodeGroup', width: 150},
141141
{title: 'cron表达式', dataIndex: 'cronExpression', width: 100},
@@ -327,7 +327,7 @@
327327
data: {jobId: jobId},
328328
success: function (json) {
329329
if (json && json.success) {
330-
BUI.Message.Alert("添加成功!");
330+
BUI.Message.Alert("删除成功!");
331331
that.parents(".bui-grid-row").remove();
332332
} else {
333333
BUI.Message.Alert("删除失败, " + json.msg);
@@ -336,12 +336,6 @@
336336
});
337337
}, 'question');
338338
});
339-
340-
$(document).on("click", ".job-logger-btn", function(){
341-
var taskId = $(this).attr("taskId");
342-
var taskTrackerNodeGroup = $(this).attr("taskTrackerNodeGroup");
343-
344-
});
345339
}
346340
347341
</script>

lts-admin/src/main/webapp/main/executable-job-queue.jsp

Lines changed: 189 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,61 @@
6262
</div>
6363
</div>
6464

65+
<div id="jobEditDlgContent" class="hidden">
66+
<form id="jobEditDlgForm" class="form-horizontal">
67+
<div class="row">
68+
<span class="hidden" id="oldJobInfo">
69+
</span>
70+
<input type="hidden" name="jobId" value=""/>
71+
<input type="hidden" name="taskTrackerNodeGroup" value=""/>
72+
73+
<div class="control-group span8">
74+
<label class="control-label">CronExpression:</label>
75+
76+
<div class="controls">
77+
<input type="text" name="cronExpression" class="input-normal control-text"
78+
data-rules="{required : true}">
79+
</div>
80+
</div>
81+
<div class="control-group span8">
82+
<label class="control-label">优先级:</label>
83+
84+
<div class="controls">
85+
<input type="text" name="priority" placeholder="数值越小,优先级越大" class="input-normal control-text"
86+
data-rules="{required : true, number:true}">
87+
</div>
88+
</div>
89+
<div class="control-group span8">
90+
<label class="control-label">提交节点组:</label>
91+
92+
<div class="controls">
93+
<input type="text" name="submitNodeGroup" class="input-normal control-text"
94+
data-rules="{required : true}">
95+
</div>
96+
</div>
97+
<div class="control-group span8">
98+
<label class="control-label">反馈客户端:</label>
99+
100+
<div class="controls">
101+
<select class="input-normal" name="needFeedback">
102+
<option value="true">是</option>
103+
<option value="false">否</option>
104+
</select>
105+
</div>
106+
</div>
107+
</div>
108+
<div class="row">
109+
<div class="control-group span15">
110+
<label class="control-label">用户参数(JSON):</label>
111+
112+
<div class="controls control-row4">
113+
<textarea class="input-large" name="extParams" type="text"></textarea>
114+
</div>
115+
</div>
116+
</div>
117+
</form>
118+
</div>
119+
65120
<script type="text/javascript">
66121
BUI.use('common/page');
67122
</script>
@@ -72,7 +127,7 @@
72127
function buiInit(BUI, Grid, Form, Data, Overlay, DateUtil) {
73128
74129
var columns = [
75-
{title: '任务ID', dataIndex: 'taskId', width: 230, sortable: false},
130+
{title: '任务ID', dataIndex: 'taskId', width: 240, sortable: false},
76131
{title: '提交节点组', dataIndex: 'submitNodeGroup', width: 150},
77132
{title: '执行节点组', dataIndex: 'taskTrackerNodeGroup', width: 150},
78133
{
@@ -111,7 +166,9 @@
111166
{
112167
title: '操作', dataIndex: '', width: 90, sortable: false, renderer: function (value, obj) {
113168
var logUrl = "/job-logger/job-logger.htm?taskId=" + obj.taskId + "&taskTrackerNodeGroup=" + obj.taskTrackerNodeGroup;
114-
return '<a target="_blank" href="'+ logUrl +'">日志</a>';
169+
return '<a target="_blank" href="' + logUrl + '">日志</a>&nbsp;' +
170+
'<a href="javascript:;" class="job-edit-btn">编辑<span class="hidden">' + JSON.stringify(obj) + '</span></a>&nbsp;' +
171+
'<a href="javascript:;" class="job-del-btn" cronExpression="' + obj.cronExpression + '" jobId="' + obj.jobId + '" taskTrackerNodeGroup="' + obj.taskTrackerNodeGroup + '">删除</a>';
115172
}
116173
}
117174
];
@@ -134,7 +191,7 @@
134191
bbar: {
135192
pagingBar: true
136193
},
137-
emptyDataTpl : '<div class="centered">查询的数据不存在</div>',
194+
emptyDataTpl: '<div class="centered">查询的数据不存在</div>',
138195
store: store
139196
});
140197
grid.render();
@@ -156,6 +213,135 @@
156213
});
157214
158215
$('#btnSearch').trigger("click");
216+
217+
var jobEditDlgForm = new Form.HForm({
218+
srcNode: '#jobEditDlgForm'
219+
}).render();
220+
221+
var editForm = $("#jobEditDlgForm");
222+
223+
var jobEditDlg = new Overlay.Dialog({
224+
title: '修改定时任务',
225+
width: 500,
226+
height: 320,
227+
contentId: 'jobEditDlgContent',
228+
success: function () {
229+
230+
if (!jobEditDlgForm.isValid()) {
231+
return;
232+
}
233+
234+
// 判断时间
235+
// 提交表单,查看修改了哪些属性
236+
var oldJob = JSON.parse(editForm.find("#oldJobInfo").text());
237+
var updateJSON = {jobId: oldJob.jobId};
238+
var cronExpression = editForm.find("input[name='cronExpression']").val();
239+
if (cronExpression.trim() != oldJob.cronExpression) {
240+
// 表示修改了
241+
updateJSON['cronExpression'] = cronExpression;
242+
}
243+
var priority = editForm.find("input[name='priority']").val();
244+
if (priority.trim() != (oldJob.priority + '')) {
245+
updateJSON['priority'] = priority;
246+
}
247+
var needFeedback = editForm.find("select[name='needFeedback']").val();
248+
if (needFeedback.trim() != (oldJob.needFeedback + '')) {
249+
updateJSON['needFeedback'] = needFeedback;
250+
}
251+
var extParams = editForm.find("textarea[name='extParams']").val();
252+
if (!extParams) {
253+
extParams = '{}';
254+
}
255+
// 验证是不是JSON
256+
try {
257+
JSON.parse(extParams.trim());
258+
} catch (e) {
259+
BUI.Message.Alert("请输入正确的用户参数,JSON格式!");
260+
return;
261+
}
262+
if (extParams.trim() != JSON.stringify(oldJob.extParams)) {
263+
updateJSON['extParams'] = extParams;
264+
}
265+
var taskTrackerNodeGroup = editForm.find("input[name='taskTrackerNodeGroup']").val();
266+
updateJSON['taskTrackerNodeGroup'] = taskTrackerNodeGroup;
267+
var submitNodeGroup = editForm.find("input[name='submitNodeGroup']").val();
268+
if (submitNodeGroup.trim() != oldJob.submitNodeGroup) {
269+
updateJSON['submitNodeGroup'] = submitNodeGroup;
270+
}
271+
272+
// 判断是否修改过
273+
console.log(updateJSON);
274+
var modified = false;
275+
for (var key in updateJSON) {
276+
if (key != 'jobId') {
277+
modified = true;
278+
break;
279+
}
280+
}
281+
if (modified) {
282+
// 请求修改数据
283+
$.ajax({
284+
url: '/api/job-queue/executable-job-update',
285+
type: 'POST',
286+
dataType: 'json',
287+
data: updateJSON,
288+
success: function (json) {
289+
if (json && json.success) {
290+
BUI.Message.Alert("修改成功");
291+
location.reload();
292+
} else {
293+
BUI.Message.Alert("修改失败, " + json.msg);
294+
}
295+
}
296+
});
297+
} else {
298+
jobEditDlg.close();
299+
}
300+
}
301+
});
302+
303+
// 编辑按钮
304+
$(document).on("click", ".job-edit-btn", function () {
305+
var jobText = $(this).children("span").text();
306+
var job = JSON.parse(jobText);
307+
editForm.find("#oldJobInfo").html(jobText);
308+
editForm.find("input[name='jobId']").val(job.jobId);
309+
editForm.find("input[name='cronExpression']").val(job.cronExpression);
310+
editForm.find("input[name='priority']").val(job.priority);
311+
editForm.find("input[name='submitNodeGroup']").val(job.submitNodeGroup);
312+
editForm.find("input[name='taskTrackerNodeGroup']").val(job.taskTrackerNodeGroup);
313+
editForm.find("select[name='needFeedback']").val("" + job.needFeedback);
314+
editForm.find("textarea[name='extParams']").val(JSON.stringify(job.extParams));
315+
jobEditDlg.show();
316+
});
317+
318+
$(document).on("click", ".job-del-btn", function () {
319+
var jobId = $(this).attr("jobId");
320+
var taskTrackerNodeGroup = $(this).attr("taskTrackerNodeGroup");
321+
var cronExpression = $(this).attr("cronExpression");
322+
var msg = "确认要删除该条任务吗?";
323+
if (cronExpression) {
324+
msg = msg + " 该条是Cron Job 删除将影响下次执行,记得在定时队列管理中也将该任务删除掉!";
325+
}
326+
327+
var that = $(this);
328+
BUI.Message.Confirm(msg, function () {
329+
$.ajax({
330+
url: '/api/job-queue/executable-job-delete',
331+
type: 'POST',
332+
dataType: 'json',
333+
data: {jobId: jobId, taskTrackerNodeGroup: taskTrackerNodeGroup},
334+
success: function (json) {
335+
if (json && json.success) {
336+
BUI.Message.Alert("删除成功!");
337+
that.parents(".bui-grid-row").remove();
338+
} else {
339+
BUI.Message.Alert("删除失败, " + json.msg);
340+
}
341+
}
342+
});
343+
}, 'question');
344+
});
159345
}
160346
161347
</script>

lts-admin/src/main/webapp/main/executing-job-queue.jsp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
function buiInit(BUI, Grid, Form, Data, Overlay, DateUtil) {
8282
8383
var columns = [
84-
{title: '任务ID', dataIndex: 'taskId', width: 230, sortable: false},
84+
{title: '任务ID', dataIndex: 'taskId', width: 240, sortable: false},
8585
{title: '提交节点组', dataIndex: 'submitNodeGroup', width: 150},
8686
{title: '执行节点组', dataIndex: 'taskTrackerNodeGroup', width: 150},
8787
{title: 'cron表达式', dataIndex: 'cronExpression', width: 100},

lts-core/src/main/java/com/lts/core/support/LoggerName.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.lts.core.support;
22

33
/**
4-
* Created by hugui on 6/13/15.
4+
* @author Robert HG (254963746@qq.com) on 6/13/15.
55
*/
66
public interface LoggerName {
77

lts-jobtracker/src/main/java/com/lts/jobtracker/processor/JobFinishedProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand
9595
// 2. log info
9696
log(requestBody.isReSend(), requestBody.getIdentity(), results);
9797

98-
LOGGER.info("Job exec finished : {}", results);
98+
LOGGER.info("Job execute finished : {}", results);
9999

100100
// 3. process
101101
return process(requestBody.isReceiveNewJob(), requestBody.getNodeGroup(),

0 commit comments

Comments
 (0)