xm
2024-06-14 722af26bc6fec32bb289b1df51a9016a4935610f
提交 | 用户 | 时间
722af2 1 package com.xxl.job.admin.service.impl;
X 2
3 import com.xxl.job.admin.core.cron.CronExpression;
4 import com.xxl.job.admin.core.model.XxlJobGroup;
5 import com.xxl.job.admin.core.model.XxlJobInfo;
6 import com.xxl.job.admin.core.model.XxlJobLogReport;
7 import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
8 import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
9 import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
10 import com.xxl.job.admin.core.thread.JobScheduleHelper;
11 import com.xxl.job.admin.core.util.I18nUtil;
12 import com.xxl.job.admin.dao.*;
13 import com.xxl.job.admin.service.XxlJobService;
14 import com.xxl.job.core.biz.model.ReturnT;
15 import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
16 import com.xxl.job.core.glue.GlueTypeEnum;
17 import com.xxl.job.core.util.DateUtil;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20 import org.springframework.stereotype.Service;
21
22 import javax.annotation.Resource;
23 import java.text.MessageFormat;
24 import java.util.*;
25
26 /**
27  * core job action for xxl-job
28  *
29  * @author xuxueli 2016-5-28 15:30:33
30  */
31 @Service
32 public class XxlJobServiceImpl implements XxlJobService {
33     private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);
34
35     @Resource
36     private XxlJobGroupDao xxlJobGroupDao;
37     @Resource
38     private XxlJobInfoDao xxlJobInfoDao;
39     @Resource
40     public XxlJobLogDao xxlJobLogDao;
41     @Resource
42     private XxlJobLogGlueDao xxlJobLogGlueDao;
43     @Resource
44     private XxlJobLogReportDao xxlJobLogReportDao;
45
46     @Override
47     public Map<String, Object> pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
48
49         // page list
50         List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
51         int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
52
53         // package result
54         Map<String, Object> maps = new HashMap<String, Object>();
55         maps.put("recordsTotal", list_count);        // 总记录数
56         maps.put("recordsFiltered", list_count);    // 过滤后的总记录数
57         maps.put("data", list);                    // 分页列表
58         return maps;
59     }
60
61     @Override
62     public ReturnT<String> add(XxlJobInfo jobInfo) {
63
64         // valid base
65         XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
66         if (group == null) {
67             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_field_jobgroup")));
68         }
69         if (jobInfo.getJobDesc() == null || jobInfo.getJobDesc().trim().length() == 0) {
70             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc")));
71         }
72         if (jobInfo.getAuthor() == null || jobInfo.getAuthor().trim().length() == 0) {
73             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author")));
74         }
75
76         // valid trigger
77         ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
78         if (scheduleTypeEnum == null) {
79             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
80         }
81         if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {
82             if (jobInfo.getScheduleConf() == null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {
83                 return new ReturnT<String>(ReturnT.FAIL_CODE, "Cron" + I18nUtil.getString("system_unvalid"));
84             }
85         } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE/* || scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {
86             if (jobInfo.getScheduleConf() == null) {
87                 return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")));
88             }
89             try {
90                 int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());
91                 if (fixSecond < 1) {
92                     return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
93                 }
94             } catch (Exception e) {
95                 return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
96             }
97         }
98
99         // valid job
100         if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
101             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype") + I18nUtil.getString("system_unvalid")));
102         }
103         if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler() == null || jobInfo.getExecutorHandler().trim().length() == 0)) {
104             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + "JobHandler"));
105         }
106         // 》fix "\r" in shell
107         if (GlueTypeEnum.GLUE_SHELL == GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource() != null) {
108             jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));
109         }
110
111         // valid advanced
112         if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
113             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_unvalid")));
114         }
115         if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {
116             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_unvalid")));
117         }
118         if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
119             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_unvalid")));
120         }
121
122         // 》ChildJobId valid
123         if (jobInfo.getChildJobId() != null && jobInfo.getChildJobId().trim().length() > 0) {
124             String[] childJobIds = jobInfo.getChildJobId().split(",");
125             for (String childJobIdItem : childJobIds) {
126                 if (childJobIdItem != null && childJobIdItem.trim().length() > 0 && isNumeric(childJobIdItem)) {
127                     XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));
128                     if (childJobInfo == null) {
129                         return new ReturnT<String>(ReturnT.FAIL_CODE,
130                             MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_not_found")), childJobIdItem));
131                     }
132                 } else {
133                     return new ReturnT<String>(ReturnT.FAIL_CODE,
134                         MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_unvalid")), childJobIdItem));
135                 }
136             }
137
138             // join , avoid "xxx,,"
139             String temp = "";
140             for (String item : childJobIds) {
141                 temp += item + ",";
142             }
143             temp = temp.substring(0, temp.length() - 1);
144
145             jobInfo.setChildJobId(temp);
146         }
147
148         // add in db
149         jobInfo.setAddTime(new Date());
150         jobInfo.setUpdateTime(new Date());
151         jobInfo.setGlueUpdatetime(new Date());
152         xxlJobInfoDao.save(jobInfo);
153         if (jobInfo.getId() < 1) {
154             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add") + I18nUtil.getString("system_fail")));
155         }
156
157         return new ReturnT<String>(String.valueOf(jobInfo.getId()));
158     }
159
160     private boolean isNumeric(String str) {
161         try {
162             int result = Integer.valueOf(str);
163             return true;
164         } catch (NumberFormatException e) {
165             return false;
166         }
167     }
168
169     @Override
170     public ReturnT<String> update(XxlJobInfo jobInfo) {
171
172         // valid base
173         if (jobInfo.getJobDesc() == null || jobInfo.getJobDesc().trim().length() == 0) {
174             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc")));
175         }
176         if (jobInfo.getAuthor() == null || jobInfo.getAuthor().trim().length() == 0) {
177             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author")));
178         }
179
180         // valid trigger
181         ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
182         if (scheduleTypeEnum == null) {
183             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
184         }
185         if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {
186             if (jobInfo.getScheduleConf() == null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {
187                 return new ReturnT<String>(ReturnT.FAIL_CODE, "Cron" + I18nUtil.getString("system_unvalid"));
188             }
189         } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE /*|| scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {
190             if (jobInfo.getScheduleConf() == null) {
191                 return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
192             }
193             try {
194                 int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());
195                 if (fixSecond < 1) {
196                     return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
197                 }
198             } catch (Exception e) {
199                 return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
200             }
201         }
202
203         // valid advanced
204         if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
205             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_unvalid")));
206         }
207         if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {
208             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_unvalid")));
209         }
210         if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
211             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_unvalid")));
212         }
213
214         // 》ChildJobId valid
215         if (jobInfo.getChildJobId() != null && jobInfo.getChildJobId().trim().length() > 0) {
216             String[] childJobIds = jobInfo.getChildJobId().split(",");
217             for (String childJobIdItem : childJobIds) {
218                 if (childJobIdItem != null && childJobIdItem.trim().length() > 0 && isNumeric(childJobIdItem)) {
219                     XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));
220                     if (childJobInfo == null) {
221                         return new ReturnT<String>(ReturnT.FAIL_CODE,
222                             MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_not_found")), childJobIdItem));
223                     }
224                 } else {
225                     return new ReturnT<String>(ReturnT.FAIL_CODE,
226                         MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_unvalid")), childJobIdItem));
227                 }
228             }
229
230             // join , avoid "xxx,,"
231             String temp = "";
232             for (String item : childJobIds) {
233                 temp += item + ",";
234             }
235             temp = temp.substring(0, temp.length() - 1);
236
237             jobInfo.setChildJobId(temp);
238         }
239
240         // group valid
241         XxlJobGroup jobGroup = xxlJobGroupDao.load(jobInfo.getJobGroup());
242         if (jobGroup == null) {
243             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_jobgroup") + I18nUtil.getString("system_unvalid")));
244         }
245
246         // stage job info
247         XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());
248         if (exists_jobInfo == null) {
249             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_not_found")));
250         }
251
252         // next trigger time (5s后生效,避开预读周期)
253         long nextTriggerTime = exists_jobInfo.getTriggerNextTime();
254         boolean scheduleDataNotChanged = jobInfo.getScheduleType().equals(exists_jobInfo.getScheduleType()) && jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf());
255         if (exists_jobInfo.getTriggerStatus() == 1 && !scheduleDataNotChanged) {
256             try {
257                 Date nextValidTime = JobScheduleHelper.generateNextValidTime(jobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
258                 if (nextValidTime == null) {
259                     return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
260                 }
261                 nextTriggerTime = nextValidTime.getTime();
262             } catch (Exception e) {
263                 logger.error(e.getMessage(), e);
264                 return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
265             }
266         }
267
268         exists_jobInfo.setJobGroup(jobInfo.getJobGroup());
269         exists_jobInfo.setJobDesc(jobInfo.getJobDesc());
270         exists_jobInfo.setAuthor(jobInfo.getAuthor());
271         exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());
272         exists_jobInfo.setScheduleType(jobInfo.getScheduleType());
273         exists_jobInfo.setScheduleConf(jobInfo.getScheduleConf());
274         exists_jobInfo.setMisfireStrategy(jobInfo.getMisfireStrategy());
275         exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());
276         exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler());
277         exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());
278         exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
279         exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());
280         exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());
281         exists_jobInfo.setChildJobId(jobInfo.getChildJobId());
282         exists_jobInfo.setTriggerNextTime(nextTriggerTime);
283
284         exists_jobInfo.setUpdateTime(new Date());
285         xxlJobInfoDao.update(exists_jobInfo);
286
287
288         return ReturnT.SUCCESS;
289     }
290
291     @Override
292     public ReturnT<String> remove(int id) {
293         XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
294         if (xxlJobInfo == null) {
295             return ReturnT.SUCCESS;
296         }
297
298         xxlJobInfoDao.delete(id);
299         xxlJobLogDao.delete(id);
300         xxlJobLogGlueDao.deleteByJobId(id);
301         return ReturnT.SUCCESS;
302     }
303
304     @Override
305     public ReturnT<String> start(int id) {
306         XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
307
308         // valid
309         ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(xxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE);
310         if (ScheduleTypeEnum.NONE == scheduleTypeEnum) {
311             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type_none_limit_start")));
312         }
313
314         // next trigger time (5s后生效,避开预读周期)
315         long nextTriggerTime = 0;
316         try {
317             Date nextValidTime = JobScheduleHelper.generateNextValidTime(xxlJobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
318             if (nextValidTime == null) {
319                 return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
320             }
321             nextTriggerTime = nextValidTime.getTime();
322         } catch (Exception e) {
323             logger.error(e.getMessage(), e);
324             return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
325         }
326
327         xxlJobInfo.setTriggerStatus(1);
328         xxlJobInfo.setTriggerLastTime(0);
329         xxlJobInfo.setTriggerNextTime(nextTriggerTime);
330
331         xxlJobInfo.setUpdateTime(new Date());
332         xxlJobInfoDao.update(xxlJobInfo);
333         return ReturnT.SUCCESS;
334     }
335
336     @Override
337     public ReturnT<String> stop(int id) {
338         XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
339
340         xxlJobInfo.setTriggerStatus(0);
341         xxlJobInfo.setTriggerLastTime(0);
342         xxlJobInfo.setTriggerNextTime(0);
343
344         xxlJobInfo.setUpdateTime(new Date());
345         xxlJobInfoDao.update(xxlJobInfo);
346         return ReturnT.SUCCESS;
347     }
348
349     @Override
350     public Map<String, Object> dashboardInfo() {
351
352         int jobInfoCount = xxlJobInfoDao.findAllCount();
353         int jobLogCount = 0;
354         int jobLogSuccessCount = 0;
355         XxlJobLogReport xxlJobLogReport = xxlJobLogReportDao.queryLogReportTotal();
356         if (xxlJobLogReport != null) {
357             jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount();
358             jobLogSuccessCount = xxlJobLogReport.getSucCount();
359         }
360
361         // executor count
362         Set<String> executorAddressSet = new HashSet<String>();
363         List<XxlJobGroup> groupList = xxlJobGroupDao.findAll();
364
365         if (groupList != null && !groupList.isEmpty()) {
366             for (XxlJobGroup group : groupList) {
367                 if (group.getRegistryList() != null && !group.getRegistryList().isEmpty()) {
368                     executorAddressSet.addAll(group.getRegistryList());
369                 }
370             }
371         }
372
373         int executorCount = executorAddressSet.size();
374
375         Map<String, Object> dashboardMap = new HashMap<String, Object>();
376         dashboardMap.put("jobInfoCount", jobInfoCount);
377         dashboardMap.put("jobLogCount", jobLogCount);
378         dashboardMap.put("jobLogSuccessCount", jobLogSuccessCount);
379         dashboardMap.put("executorCount", executorCount);
380         return dashboardMap;
381     }
382
383     @Override
384     public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
385
386         // process
387         List<String> triggerDayList = new ArrayList<String>();
388         List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();
389         List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
390         List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
391         int triggerCountRunningTotal = 0;
392         int triggerCountSucTotal = 0;
393         int triggerCountFailTotal = 0;
394
395         List<XxlJobLogReport> logReportList = xxlJobLogReportDao.queryLogReport(startDate, endDate);
396
397         if (logReportList != null && logReportList.size() > 0) {
398             for (XxlJobLogReport item : logReportList) {
399                 String day = DateUtil.formatDate(item.getTriggerDay());
400                 int triggerDayCountRunning = item.getRunningCount();
401                 int triggerDayCountSuc = item.getSucCount();
402                 int triggerDayCountFail = item.getFailCount();
403
404                 triggerDayList.add(day);
405                 triggerDayCountRunningList.add(triggerDayCountRunning);
406                 triggerDayCountSucList.add(triggerDayCountSuc);
407                 triggerDayCountFailList.add(triggerDayCountFail);
408
409                 triggerCountRunningTotal += triggerDayCountRunning;
410                 triggerCountSucTotal += triggerDayCountSuc;
411                 triggerCountFailTotal += triggerDayCountFail;
412             }
413         } else {
414             for (int i = -6; i <= 0; i++) {
415                 triggerDayList.add(DateUtil.formatDate(DateUtil.addDays(new Date(), i)));
416                 triggerDayCountRunningList.add(0);
417                 triggerDayCountSucList.add(0);
418                 triggerDayCountFailList.add(0);
419             }
420         }
421
422         Map<String, Object> result = new HashMap<String, Object>();
423         result.put("triggerDayList", triggerDayList);
424         result.put("triggerDayCountRunningList", triggerDayCountRunningList);
425         result.put("triggerDayCountSucList", triggerDayCountSucList);
426         result.put("triggerDayCountFailList", triggerDayCountFailList);
427
428         result.put("triggerCountRunningTotal", triggerCountRunningTotal);
429         result.put("triggerCountSucTotal", triggerCountSucTotal);
430         result.put("triggerCountFailTotal", triggerCountFailTotal);
431
432         return new ReturnT<Map<String, Object>>(result);
433     }
434
435 }