diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
deleted file mode 100644
index 3bc58d7..0000000
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xxl.job.core.resolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import com.xxl.job.client.util.JacksonUtil;
-import com.xxl.job.core.model.ReturnT;
-
-/**
- * common exception resolver
- * @author xuxueli 2016-1-6 19:22:18
- */
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- logger.error("system catch exception:{}", ex);
-
- ModelAndView mv = new ModelAndView();
- HandlerMethod method = (HandlerMethod)handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
- mv.setViewName("/common/common.result");
- } else {
- mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
- mv.setViewName("/common/common.exception");
- }
- return mv;
- }
-
-}
\ No newline at end of file
diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
deleted file mode 100644
index 3bc58d7..0000000
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xxl.job.core.resolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import com.xxl.job.client.util.JacksonUtil;
-import com.xxl.job.core.model.ReturnT;
-
-/**
- * common exception resolver
- * @author xuxueli 2016-1-6 19:22:18
- */
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- logger.error("system catch exception:{}", ex);
-
- ModelAndView mv = new ModelAndView();
- HandlerMethod method = (HandlerMethod)handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
- mv.setViewName("/common/common.result");
- } else {
- mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
- mv.setViewName("/common/common.exception");
- }
- return mv;
- }
-
-}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
new file mode 100644
index 0000000..c322d9c
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
@@ -0,0 +1,82 @@
+package com.xxl.job.core.thread;
+
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.xxl.job.client.util.HttpUtil;
+import com.xxl.job.core.model.XxlJobInfo;
+import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.util.DynamicSchedulerUtil;
+import com.xxl.job.core.util.MailUtil;
+
+/**
+ * job monitor helper
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobMonitorHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class);
+
+ public static JobMonitorHelper helper = new JobMonitorHelper();
+ private ExecutorService executor = Executors.newCachedThreadPool();
+ private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8);
+ private ConcurrentHashMap countMap = new ConcurrentHashMap();
+
+ public JobMonitorHelper(){
+ // consumer
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ logger.info(">>>>>>>>>>> job monitor run ... ");
+ Integer jobLogId = JobMonitorHelper.helper.queue.poll();
+ if (jobLogId != null && jobLogId > 0) {
+ XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId);
+ if (log!=null) {
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) {
+ JobMonitorHelper.monitor(jobLogId);
+ }
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) {
+ // pass
+ }
+ if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) {
+ String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName());
+ Integer count = countMap.get(monotorKey);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ count += 1;
+ countMap.put(monotorKey, count);
+ XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName());
+ if (count >= info.getAlarmThreshold()) {
+ MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》",
+ MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null);
+ countMap.remove(monotorKey);
+ }
+ }
+ }
+ } else {
+ try {
+ TimeUnit.SECONDS.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ // producer
+ public static void monitor(int jobLogId){
+ JobMonitorHelper.helper.queue.offer(jobLogId);
+ }
+
+}
diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
deleted file mode 100644
index 3bc58d7..0000000
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xxl.job.core.resolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import com.xxl.job.client.util.JacksonUtil;
-import com.xxl.job.core.model.ReturnT;
-
-/**
- * common exception resolver
- * @author xuxueli 2016-1-6 19:22:18
- */
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- logger.error("system catch exception:{}", ex);
-
- ModelAndView mv = new ModelAndView();
- HandlerMethod method = (HandlerMethod)handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
- mv.setViewName("/common/common.result");
- } else {
- mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
- mv.setViewName("/common/common.exception");
- }
- return mv;
- }
-
-}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
new file mode 100644
index 0000000..c322d9c
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
@@ -0,0 +1,82 @@
+package com.xxl.job.core.thread;
+
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.xxl.job.client.util.HttpUtil;
+import com.xxl.job.core.model.XxlJobInfo;
+import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.util.DynamicSchedulerUtil;
+import com.xxl.job.core.util.MailUtil;
+
+/**
+ * job monitor helper
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobMonitorHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class);
+
+ public static JobMonitorHelper helper = new JobMonitorHelper();
+ private ExecutorService executor = Executors.newCachedThreadPool();
+ private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8);
+ private ConcurrentHashMap countMap = new ConcurrentHashMap();
+
+ public JobMonitorHelper(){
+ // consumer
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ logger.info(">>>>>>>>>>> job monitor run ... ");
+ Integer jobLogId = JobMonitorHelper.helper.queue.poll();
+ if (jobLogId != null && jobLogId > 0) {
+ XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId);
+ if (log!=null) {
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) {
+ JobMonitorHelper.monitor(jobLogId);
+ }
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) {
+ // pass
+ }
+ if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) {
+ String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName());
+ Integer count = countMap.get(monotorKey);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ count += 1;
+ countMap.put(monotorKey, count);
+ XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName());
+ if (count >= info.getAlarmThreshold()) {
+ MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》",
+ MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null);
+ countMap.remove(monotorKey);
+ }
+ }
+ }
+ } else {
+ try {
+ TimeUnit.SECONDS.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ // producer
+ public static void monitor(int jobLogId){
+ JobMonitorHelper.helper.queue.offer(jobLogId);
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
index 1b06f65..ef675c7 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
@@ -67,6 +67,7 @@
}
// getJobKeys
+ @Deprecated
public static List
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
deleted file mode 100644
index 3bc58d7..0000000
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xxl.job.core.resolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import com.xxl.job.client.util.JacksonUtil;
-import com.xxl.job.core.model.ReturnT;
-
-/**
- * common exception resolver
- * @author xuxueli 2016-1-6 19:22:18
- */
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- logger.error("system catch exception:{}", ex);
-
- ModelAndView mv = new ModelAndView();
- HandlerMethod method = (HandlerMethod)handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
- mv.setViewName("/common/common.result");
- } else {
- mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
- mv.setViewName("/common/common.exception");
- }
- return mv;
- }
-
-}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
new file mode 100644
index 0000000..c322d9c
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
@@ -0,0 +1,82 @@
+package com.xxl.job.core.thread;
+
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.xxl.job.client.util.HttpUtil;
+import com.xxl.job.core.model.XxlJobInfo;
+import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.util.DynamicSchedulerUtil;
+import com.xxl.job.core.util.MailUtil;
+
+/**
+ * job monitor helper
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobMonitorHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class);
+
+ public static JobMonitorHelper helper = new JobMonitorHelper();
+ private ExecutorService executor = Executors.newCachedThreadPool();
+ private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8);
+ private ConcurrentHashMap countMap = new ConcurrentHashMap();
+
+ public JobMonitorHelper(){
+ // consumer
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ logger.info(">>>>>>>>>>> job monitor run ... ");
+ Integer jobLogId = JobMonitorHelper.helper.queue.poll();
+ if (jobLogId != null && jobLogId > 0) {
+ XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId);
+ if (log!=null) {
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) {
+ JobMonitorHelper.monitor(jobLogId);
+ }
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) {
+ // pass
+ }
+ if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) {
+ String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName());
+ Integer count = countMap.get(monotorKey);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ count += 1;
+ countMap.put(monotorKey, count);
+ XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName());
+ if (count >= info.getAlarmThreshold()) {
+ MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》",
+ MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null);
+ countMap.remove(monotorKey);
+ }
+ }
+ }
+ } else {
+ try {
+ TimeUnit.SECONDS.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ // producer
+ public static void monitor(int jobLogId){
+ JobMonitorHelper.helper.queue.offer(jobLogId);
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
index 1b06f65..ef675c7 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
@@ -67,6 +67,7 @@
}
// getJobKeys
+ @Deprecated
public static List> getJobList(){
List> jobList = new ArrayList>();
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
new file mode 100644
index 0000000..ff2204d
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
@@ -0,0 +1,181 @@
+package com.xxl.job.core.util;
+
+import java.io.File;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeUtility;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+
+/**
+ * 邮件发送.Util
+ * @author xuxueli 2016-3-12 15:06:20
+ */
+public class MailUtil {
+ private static Logger logger = LoggerFactory.getLogger(MailUtil.class);
+
+ private static String host;
+ private static String port;
+ private static String username;
+ private static String password;
+ private static String sendFrom;
+ private static String sendNick;
+ static{
+ host = PropertiesUtil.getString("mail.host");
+ port = PropertiesUtil.getString("mail.port");
+ username = PropertiesUtil.getString("mail.username");
+ password = PropertiesUtil.getString("mail.password");
+ sendFrom = PropertiesUtil.getString("mail.sendFrom");
+ sendNick = PropertiesUtil.getString("mail.sendNick");
+ }
+
+ /**
+
+
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+ */
+ /**
+ * 发送邮件 (完整版)(结合Spring)
+ *
+ * @param javaMailSender: 发送Bean
+ * @param sendFrom : 发送人邮箱
+ * @param sendNick : 发送人昵称
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param files[] : 附件
+ */
+ @SuppressWarnings("null")
+ public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) {
+ JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender();
+ try {
+ MimeMessage mimeMessage = javaMailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ // 设置收件人抄送的名片和地址(相当于群发了)
+ //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>"));
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ // 群发
+ //MimeMessage[] mailMessages = { mimeMessage };
+
+ javaMailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ logger.info("{}", e);
+ }
+ return false;
+ }
+
+ /**
+ * 发送邮件 (完整版) (纯JavaMail)
+ *
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param inLineFile : 内嵌文件
+ * @param files[] : 附件
+ */
+ public static boolean sendMail (String toAddress, String mailSubject, String mailBody,
+ boolean mailBodyIsHtml, File[] attachments){
+ try {
+ // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 )
+ JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+ mailSender.setHost(host); // 设置邮件服务主机
+ mailSender.setUsername(username); // 发送者邮箱的用户名
+ mailSender.setPassword(password); // 发送者邮箱的密码
+
+ //配置文件,用于实例化java.mail.session
+ Properties pro = System.getProperties();
+ pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权)
+ pro.put("mail.smtp.socketFactory.port", port);
+ pro.put("mail.smtp.socketFactory.fallback", "false");
+ mailSender.setJavaMailProperties(pro);
+
+ //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage)
+ MimeMessage mimeMessage = mailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8");
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源
+ //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ mailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ static int total = 0;
+ public static void main(String[] args) {
+
+ ExecutorService exec = Executors.newCachedThreadPool();
+ for (int i = 0; i < 20; i++) {
+ exec.execute(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while(total < 10){
+ String mailBody = "新书快递通知
你的新书快递申请已推送新书,请到空间"
+ + "中查看";
+
+ sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null);
+ System.out.println(total);
+ total++;
+ }
+ }
+ }));
+ }
+ }
+
+}
diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
deleted file mode 100644
index 3bc58d7..0000000
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xxl.job.core.resolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import com.xxl.job.client.util.JacksonUtil;
-import com.xxl.job.core.model.ReturnT;
-
-/**
- * common exception resolver
- * @author xuxueli 2016-1-6 19:22:18
- */
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- logger.error("system catch exception:{}", ex);
-
- ModelAndView mv = new ModelAndView();
- HandlerMethod method = (HandlerMethod)handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
- mv.setViewName("/common/common.result");
- } else {
- mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
- mv.setViewName("/common/common.exception");
- }
- return mv;
- }
-
-}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
new file mode 100644
index 0000000..c322d9c
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
@@ -0,0 +1,82 @@
+package com.xxl.job.core.thread;
+
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.xxl.job.client.util.HttpUtil;
+import com.xxl.job.core.model.XxlJobInfo;
+import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.util.DynamicSchedulerUtil;
+import com.xxl.job.core.util.MailUtil;
+
+/**
+ * job monitor helper
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobMonitorHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class);
+
+ public static JobMonitorHelper helper = new JobMonitorHelper();
+ private ExecutorService executor = Executors.newCachedThreadPool();
+ private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8);
+ private ConcurrentHashMap countMap = new ConcurrentHashMap();
+
+ public JobMonitorHelper(){
+ // consumer
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ logger.info(">>>>>>>>>>> job monitor run ... ");
+ Integer jobLogId = JobMonitorHelper.helper.queue.poll();
+ if (jobLogId != null && jobLogId > 0) {
+ XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId);
+ if (log!=null) {
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) {
+ JobMonitorHelper.monitor(jobLogId);
+ }
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) {
+ // pass
+ }
+ if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) {
+ String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName());
+ Integer count = countMap.get(monotorKey);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ count += 1;
+ countMap.put(monotorKey, count);
+ XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName());
+ if (count >= info.getAlarmThreshold()) {
+ MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》",
+ MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null);
+ countMap.remove(monotorKey);
+ }
+ }
+ }
+ } else {
+ try {
+ TimeUnit.SECONDS.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ // producer
+ public static void monitor(int jobLogId){
+ JobMonitorHelper.helper.queue.offer(jobLogId);
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
index 1b06f65..ef675c7 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
@@ -67,6 +67,7 @@
}
// getJobKeys
+ @Deprecated
public static List> getJobList(){
List> jobList = new ArrayList>();
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
new file mode 100644
index 0000000..ff2204d
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
@@ -0,0 +1,181 @@
+package com.xxl.job.core.util;
+
+import java.io.File;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeUtility;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+
+/**
+ * 邮件发送.Util
+ * @author xuxueli 2016-3-12 15:06:20
+ */
+public class MailUtil {
+ private static Logger logger = LoggerFactory.getLogger(MailUtil.class);
+
+ private static String host;
+ private static String port;
+ private static String username;
+ private static String password;
+ private static String sendFrom;
+ private static String sendNick;
+ static{
+ host = PropertiesUtil.getString("mail.host");
+ port = PropertiesUtil.getString("mail.port");
+ username = PropertiesUtil.getString("mail.username");
+ password = PropertiesUtil.getString("mail.password");
+ sendFrom = PropertiesUtil.getString("mail.sendFrom");
+ sendNick = PropertiesUtil.getString("mail.sendNick");
+ }
+
+ /**
+
+
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+ */
+ /**
+ * 发送邮件 (完整版)(结合Spring)
+ *
+ * @param javaMailSender: 发送Bean
+ * @param sendFrom : 发送人邮箱
+ * @param sendNick : 发送人昵称
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param files[] : 附件
+ */
+ @SuppressWarnings("null")
+ public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) {
+ JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender();
+ try {
+ MimeMessage mimeMessage = javaMailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ // 设置收件人抄送的名片和地址(相当于群发了)
+ //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>"));
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ // 群发
+ //MimeMessage[] mailMessages = { mimeMessage };
+
+ javaMailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ logger.info("{}", e);
+ }
+ return false;
+ }
+
+ /**
+ * 发送邮件 (完整版) (纯JavaMail)
+ *
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param inLineFile : 内嵌文件
+ * @param files[] : 附件
+ */
+ public static boolean sendMail (String toAddress, String mailSubject, String mailBody,
+ boolean mailBodyIsHtml, File[] attachments){
+ try {
+ // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 )
+ JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+ mailSender.setHost(host); // 设置邮件服务主机
+ mailSender.setUsername(username); // 发送者邮箱的用户名
+ mailSender.setPassword(password); // 发送者邮箱的密码
+
+ //配置文件,用于实例化java.mail.session
+ Properties pro = System.getProperties();
+ pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权)
+ pro.put("mail.smtp.socketFactory.port", port);
+ pro.put("mail.smtp.socketFactory.fallback", "false");
+ mailSender.setJavaMailProperties(pro);
+
+ //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage)
+ MimeMessage mimeMessage = mailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8");
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源
+ //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ mailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ static int total = 0;
+ public static void main(String[] args) {
+
+ ExecutorService exec = Executors.newCachedThreadPool();
+ for (int i = 0; i < 20; i++) {
+ exec.execute(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while(total < 10){
+ String mailBody = "新书快递通知
你的新书快递申请已推送新书,请到空间"
+ + "中查看";
+
+ sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null);
+ System.out.println(total);
+ total++;
+ }
+ }
+ }));
+ }
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
index 8e522f9..9b59cf5 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
@@ -19,6 +19,7 @@
import com.xxl.job.client.util.JacksonUtil;
import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.thread.JobMonitorHelper;
import com.xxl.job.core.util.DynamicSchedulerUtil;
/**
@@ -81,6 +82,7 @@
// update trigger info
DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog);
DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog);
+ JobMonitorHelper.monitor(jobLog.getId());
logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
}
diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
deleted file mode 100644
index 3bc58d7..0000000
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xxl.job.core.resolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import com.xxl.job.client.util.JacksonUtil;
-import com.xxl.job.core.model.ReturnT;
-
-/**
- * common exception resolver
- * @author xuxueli 2016-1-6 19:22:18
- */
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- logger.error("system catch exception:{}", ex);
-
- ModelAndView mv = new ModelAndView();
- HandlerMethod method = (HandlerMethod)handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
- mv.setViewName("/common/common.result");
- } else {
- mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
- mv.setViewName("/common/common.exception");
- }
- return mv;
- }
-
-}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
new file mode 100644
index 0000000..c322d9c
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
@@ -0,0 +1,82 @@
+package com.xxl.job.core.thread;
+
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.xxl.job.client.util.HttpUtil;
+import com.xxl.job.core.model.XxlJobInfo;
+import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.util.DynamicSchedulerUtil;
+import com.xxl.job.core.util.MailUtil;
+
+/**
+ * job monitor helper
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobMonitorHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class);
+
+ public static JobMonitorHelper helper = new JobMonitorHelper();
+ private ExecutorService executor = Executors.newCachedThreadPool();
+ private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8);
+ private ConcurrentHashMap countMap = new ConcurrentHashMap();
+
+ public JobMonitorHelper(){
+ // consumer
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ logger.info(">>>>>>>>>>> job monitor run ... ");
+ Integer jobLogId = JobMonitorHelper.helper.queue.poll();
+ if (jobLogId != null && jobLogId > 0) {
+ XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId);
+ if (log!=null) {
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) {
+ JobMonitorHelper.monitor(jobLogId);
+ }
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) {
+ // pass
+ }
+ if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) {
+ String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName());
+ Integer count = countMap.get(monotorKey);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ count += 1;
+ countMap.put(monotorKey, count);
+ XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName());
+ if (count >= info.getAlarmThreshold()) {
+ MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》",
+ MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null);
+ countMap.remove(monotorKey);
+ }
+ }
+ }
+ } else {
+ try {
+ TimeUnit.SECONDS.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ // producer
+ public static void monitor(int jobLogId){
+ JobMonitorHelper.helper.queue.offer(jobLogId);
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
index 1b06f65..ef675c7 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
@@ -67,6 +67,7 @@
}
// getJobKeys
+ @Deprecated
public static List> getJobList(){
List> jobList = new ArrayList>();
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
new file mode 100644
index 0000000..ff2204d
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
@@ -0,0 +1,181 @@
+package com.xxl.job.core.util;
+
+import java.io.File;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeUtility;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+
+/**
+ * 邮件发送.Util
+ * @author xuxueli 2016-3-12 15:06:20
+ */
+public class MailUtil {
+ private static Logger logger = LoggerFactory.getLogger(MailUtil.class);
+
+ private static String host;
+ private static String port;
+ private static String username;
+ private static String password;
+ private static String sendFrom;
+ private static String sendNick;
+ static{
+ host = PropertiesUtil.getString("mail.host");
+ port = PropertiesUtil.getString("mail.port");
+ username = PropertiesUtil.getString("mail.username");
+ password = PropertiesUtil.getString("mail.password");
+ sendFrom = PropertiesUtil.getString("mail.sendFrom");
+ sendNick = PropertiesUtil.getString("mail.sendNick");
+ }
+
+ /**
+
+
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+ */
+ /**
+ * 发送邮件 (完整版)(结合Spring)
+ *
+ * @param javaMailSender: 发送Bean
+ * @param sendFrom : 发送人邮箱
+ * @param sendNick : 发送人昵称
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param files[] : 附件
+ */
+ @SuppressWarnings("null")
+ public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) {
+ JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender();
+ try {
+ MimeMessage mimeMessage = javaMailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ // 设置收件人抄送的名片和地址(相当于群发了)
+ //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>"));
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ // 群发
+ //MimeMessage[] mailMessages = { mimeMessage };
+
+ javaMailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ logger.info("{}", e);
+ }
+ return false;
+ }
+
+ /**
+ * 发送邮件 (完整版) (纯JavaMail)
+ *
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param inLineFile : 内嵌文件
+ * @param files[] : 附件
+ */
+ public static boolean sendMail (String toAddress, String mailSubject, String mailBody,
+ boolean mailBodyIsHtml, File[] attachments){
+ try {
+ // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 )
+ JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+ mailSender.setHost(host); // 设置邮件服务主机
+ mailSender.setUsername(username); // 发送者邮箱的用户名
+ mailSender.setPassword(password); // 发送者邮箱的密码
+
+ //配置文件,用于实例化java.mail.session
+ Properties pro = System.getProperties();
+ pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权)
+ pro.put("mail.smtp.socketFactory.port", port);
+ pro.put("mail.smtp.socketFactory.fallback", "false");
+ mailSender.setJavaMailProperties(pro);
+
+ //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage)
+ MimeMessage mimeMessage = mailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8");
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源
+ //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ mailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ static int total = 0;
+ public static void main(String[] args) {
+
+ ExecutorService exec = Executors.newCachedThreadPool();
+ for (int i = 0; i < 20; i++) {
+ exec.execute(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while(total < 10){
+ String mailBody = "新书快递通知
你的新书快递申请已推送新书,请到空间"
+ + "中查看";
+
+ sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null);
+ System.out.println(total);
+ total++;
+ }
+ }
+ }));
+ }
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
index 8e522f9..9b59cf5 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
@@ -19,6 +19,7 @@
import com.xxl.job.client.util.JacksonUtil;
import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.thread.JobMonitorHelper;
import com.xxl.job.core.util.DynamicSchedulerUtil;
/**
@@ -81,6 +82,7 @@
// update trigger info
DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog);
DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog);
+ JobMonitorHelper.monitor(jobLog.getId());
logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
index 7ca28fc..c15aa2c 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
@@ -18,6 +18,7 @@
import com.xxl.job.client.util.JacksonUtil;
import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.thread.JobMonitorHelper;
import com.xxl.job.core.util.DynamicSchedulerUtil;
import com.xxl.job.core.util.PropertiesUtil;
@@ -85,6 +86,7 @@
// update trigger info
DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog);
+ JobMonitorHelper.monitor(jobLog.getId());
logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
}
diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
deleted file mode 100644
index 3bc58d7..0000000
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xxl.job.core.resolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import com.xxl.job.client.util.JacksonUtil;
-import com.xxl.job.core.model.ReturnT;
-
-/**
- * common exception resolver
- * @author xuxueli 2016-1-6 19:22:18
- */
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- logger.error("system catch exception:{}", ex);
-
- ModelAndView mv = new ModelAndView();
- HandlerMethod method = (HandlerMethod)handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
- mv.setViewName("/common/common.result");
- } else {
- mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
- mv.setViewName("/common/common.exception");
- }
- return mv;
- }
-
-}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
new file mode 100644
index 0000000..c322d9c
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
@@ -0,0 +1,82 @@
+package com.xxl.job.core.thread;
+
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.xxl.job.client.util.HttpUtil;
+import com.xxl.job.core.model.XxlJobInfo;
+import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.util.DynamicSchedulerUtil;
+import com.xxl.job.core.util.MailUtil;
+
+/**
+ * job monitor helper
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobMonitorHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class);
+
+ public static JobMonitorHelper helper = new JobMonitorHelper();
+ private ExecutorService executor = Executors.newCachedThreadPool();
+ private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8);
+ private ConcurrentHashMap countMap = new ConcurrentHashMap();
+
+ public JobMonitorHelper(){
+ // consumer
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ logger.info(">>>>>>>>>>> job monitor run ... ");
+ Integer jobLogId = JobMonitorHelper.helper.queue.poll();
+ if (jobLogId != null && jobLogId > 0) {
+ XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId);
+ if (log!=null) {
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) {
+ JobMonitorHelper.monitor(jobLogId);
+ }
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) {
+ // pass
+ }
+ if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) {
+ String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName());
+ Integer count = countMap.get(monotorKey);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ count += 1;
+ countMap.put(monotorKey, count);
+ XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName());
+ if (count >= info.getAlarmThreshold()) {
+ MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》",
+ MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null);
+ countMap.remove(monotorKey);
+ }
+ }
+ }
+ } else {
+ try {
+ TimeUnit.SECONDS.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ // producer
+ public static void monitor(int jobLogId){
+ JobMonitorHelper.helper.queue.offer(jobLogId);
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
index 1b06f65..ef675c7 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
@@ -67,6 +67,7 @@
}
// getJobKeys
+ @Deprecated
public static List> getJobList(){
List> jobList = new ArrayList>();
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
new file mode 100644
index 0000000..ff2204d
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
@@ -0,0 +1,181 @@
+package com.xxl.job.core.util;
+
+import java.io.File;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeUtility;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+
+/**
+ * 邮件发送.Util
+ * @author xuxueli 2016-3-12 15:06:20
+ */
+public class MailUtil {
+ private static Logger logger = LoggerFactory.getLogger(MailUtil.class);
+
+ private static String host;
+ private static String port;
+ private static String username;
+ private static String password;
+ private static String sendFrom;
+ private static String sendNick;
+ static{
+ host = PropertiesUtil.getString("mail.host");
+ port = PropertiesUtil.getString("mail.port");
+ username = PropertiesUtil.getString("mail.username");
+ password = PropertiesUtil.getString("mail.password");
+ sendFrom = PropertiesUtil.getString("mail.sendFrom");
+ sendNick = PropertiesUtil.getString("mail.sendNick");
+ }
+
+ /**
+
+
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+ */
+ /**
+ * 发送邮件 (完整版)(结合Spring)
+ *
+ * @param javaMailSender: 发送Bean
+ * @param sendFrom : 发送人邮箱
+ * @param sendNick : 发送人昵称
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param files[] : 附件
+ */
+ @SuppressWarnings("null")
+ public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) {
+ JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender();
+ try {
+ MimeMessage mimeMessage = javaMailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ // 设置收件人抄送的名片和地址(相当于群发了)
+ //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>"));
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ // 群发
+ //MimeMessage[] mailMessages = { mimeMessage };
+
+ javaMailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ logger.info("{}", e);
+ }
+ return false;
+ }
+
+ /**
+ * 发送邮件 (完整版) (纯JavaMail)
+ *
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param inLineFile : 内嵌文件
+ * @param files[] : 附件
+ */
+ public static boolean sendMail (String toAddress, String mailSubject, String mailBody,
+ boolean mailBodyIsHtml, File[] attachments){
+ try {
+ // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 )
+ JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+ mailSender.setHost(host); // 设置邮件服务主机
+ mailSender.setUsername(username); // 发送者邮箱的用户名
+ mailSender.setPassword(password); // 发送者邮箱的密码
+
+ //配置文件,用于实例化java.mail.session
+ Properties pro = System.getProperties();
+ pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权)
+ pro.put("mail.smtp.socketFactory.port", port);
+ pro.put("mail.smtp.socketFactory.fallback", "false");
+ mailSender.setJavaMailProperties(pro);
+
+ //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage)
+ MimeMessage mimeMessage = mailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8");
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源
+ //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ mailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ static int total = 0;
+ public static void main(String[] args) {
+
+ ExecutorService exec = Executors.newCachedThreadPool();
+ for (int i = 0; i < 20; i++) {
+ exec.execute(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while(total < 10){
+ String mailBody = "新书快递通知
你的新书快递申请已推送新书,请到空间"
+ + "中查看";
+
+ sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null);
+ System.out.println(total);
+ total++;
+ }
+ }
+ }));
+ }
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
index 8e522f9..9b59cf5 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
@@ -19,6 +19,7 @@
import com.xxl.job.client.util.JacksonUtil;
import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.thread.JobMonitorHelper;
import com.xxl.job.core.util.DynamicSchedulerUtil;
/**
@@ -81,6 +82,7 @@
// update trigger info
DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog);
DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog);
+ JobMonitorHelper.monitor(jobLog.getId());
logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
index 7ca28fc..c15aa2c 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
@@ -18,6 +18,7 @@
import com.xxl.job.client.util.JacksonUtil;
import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.thread.JobMonitorHelper;
import com.xxl.job.core.util.DynamicSchedulerUtil;
import com.xxl.job.core.util.PropertiesUtil;
@@ -85,6 +86,7 @@
// update trigger info
DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog);
+ JobMonitorHelper.monitor(jobLog.getId());
logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
}
diff --git a/xxl-job-admin/src/main/resources/config.properties b/xxl-job-admin/src/main/resources/config.properties
index c22c950..574549d 100644
--- a/xxl-job-admin/src/main/resources/config.properties
+++ b/xxl-job-admin/src/main/resources/config.properties
@@ -1 +1,10 @@
-trigger_log_url=http://localhost:8080/joblog/save
\ No newline at end of file
+# for trigger log callback
+trigger_log_url=http://localhost:8080/joblog/save
+
+# for email
+mail.host=smtp.163.com
+mail.port=25
+mail.username=ovono802302@163.com
+mail.password=asdfzxcv
+mail.sendFrom=ovono802302@163.com
+mail.sendNick=《任务调度中心xxl-job》
\ No newline at end of file
diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml
index bfa25fe..192e6e6 100644
--- a/xxl-job-admin/pom.xml
+++ b/xxl-job-admin/pom.xml
@@ -130,6 +130,13 @@
4.3.6
+
+
+ javax.mail
+ mail
+ 1.4.6
+
+
org.quartz-scheduler
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
new file mode 100644
index 0000000..9060e28
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java
@@ -0,0 +1,41 @@
+package com.xxl.job.controller.resolver;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.xxl.job.client.util.JacksonUtil;
+import com.xxl.job.core.model.ReturnT;
+
+/**
+ * common exception resolver
+ * @author xuxueli 2016-1-6 19:22:18
+ */
+public class WebExceptionResolver implements HandlerExceptionResolver {
+ private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
+
+ @Override
+ public ModelAndView resolveException(HttpServletRequest request,
+ HttpServletResponse response, Object handler, Exception ex) {
+ logger.error("system catch exception:{}", ex);
+
+ ModelAndView mv = new ModelAndView();
+ HandlerMethod method = (HandlerMethod)handler;
+ ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
+ if (responseBody != null) {
+ mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
+ mv.setViewName("/common/common.result");
+ } else {
+ mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
+ mv.setViewName("/common/common.exception");
+ }
+ return mv;
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
deleted file mode 100644
index 3bc58d7..0000000
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.xxl.job.core.resolver;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import com.xxl.job.client.util.JacksonUtil;
-import com.xxl.job.core.model.ReturnT;
-
-/**
- * common exception resolver
- * @author xuxueli 2016-1-6 19:22:18
- */
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
- logger.error("system catch exception:{}", ex);
-
- ModelAndView mv = new ModelAndView();
- HandlerMethod method = (HandlerMethod)handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT(500, ex.toString().replaceAll("\n", "
"))));
- mv.setViewName("/common/common.result");
- } else {
- mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "
"));
- mv.setViewName("/common/common.exception");
- }
- return mv;
- }
-
-}
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
new file mode 100644
index 0000000..c322d9c
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java
@@ -0,0 +1,82 @@
+package com.xxl.job.core.thread;
+
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.xxl.job.client.util.HttpUtil;
+import com.xxl.job.core.model.XxlJobInfo;
+import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.util.DynamicSchedulerUtil;
+import com.xxl.job.core.util.MailUtil;
+
+/**
+ * job monitor helper
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobMonitorHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobMonitorHelper.class);
+
+ public static JobMonitorHelper helper = new JobMonitorHelper();
+ private ExecutorService executor = Executors.newCachedThreadPool();
+ private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8);
+ private ConcurrentHashMap countMap = new ConcurrentHashMap();
+
+ public JobMonitorHelper(){
+ // consumer
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ while (true) {
+ logger.info(">>>>>>>>>>> job monitor run ... ");
+ Integer jobLogId = JobMonitorHelper.helper.queue.poll();
+ if (jobLogId != null && jobLogId > 0) {
+ XxlJobLog log = DynamicSchedulerUtil.xxlJobLogDao.load(jobLogId);
+ if (log!=null) {
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && StringUtils.isBlank(log.getHandleStatus())) {
+ JobMonitorHelper.monitor(jobLogId);
+ }
+ if (HttpUtil.SUCCESS.equals(log.getTriggerStatus()) && HttpUtil.SUCCESS.equals(log.getHandleStatus())) {
+ // pass
+ }
+ if (HttpUtil.FAIL.equals(log.getTriggerStatus()) || HttpUtil.FAIL.equals(log.getHandleStatus())) {
+ String monotorKey = log.getJobGroup().concat("_").concat(log.getJobName());
+ Integer count = countMap.get(monotorKey);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ count += 1;
+ countMap.put(monotorKey, count);
+ XxlJobInfo info = DynamicSchedulerUtil.xxlJobInfoDao.load(log.getJobGroup(), log.getJobName());
+ if (count >= info.getAlarmThreshold()) {
+ MailUtil.sendMail(info.getAlarmEmail(), "《调度平台中心-监控报警》",
+ MessageFormat.format("调度任务[{0}]失败报警", monotorKey), false, null);
+ countMap.remove(monotorKey);
+ }
+ }
+ }
+ } else {
+ try {
+ TimeUnit.SECONDS.sleep(20);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ // producer
+ public static void monitor(int jobLogId){
+ JobMonitorHelper.helper.queue.offer(jobLogId);
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
index 1b06f65..ef675c7 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
@@ -67,6 +67,7 @@
}
// getJobKeys
+ @Deprecated
public static List> getJobList(){
List> jobList = new ArrayList>();
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
new file mode 100644
index 0000000..ff2204d
--- /dev/null
+++ b/xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java
@@ -0,0 +1,181 @@
+package com.xxl.job.core.util;
+
+import java.io.File;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeUtility;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+
+/**
+ * 邮件发送.Util
+ * @author xuxueli 2016-3-12 15:06:20
+ */
+public class MailUtil {
+ private static Logger logger = LoggerFactory.getLogger(MailUtil.class);
+
+ private static String host;
+ private static String port;
+ private static String username;
+ private static String password;
+ private static String sendFrom;
+ private static String sendNick;
+ static{
+ host = PropertiesUtil.getString("mail.host");
+ port = PropertiesUtil.getString("mail.port");
+ username = PropertiesUtil.getString("mail.username");
+ password = PropertiesUtil.getString("mail.password");
+ sendFrom = PropertiesUtil.getString("mail.sendFrom");
+ sendNick = PropertiesUtil.getString("mail.sendNick");
+ }
+
+ /**
+
+
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+ */
+ /**
+ * 发送邮件 (完整版)(结合Spring)
+ *
+ * @param javaMailSender: 发送Bean
+ * @param sendFrom : 发送人邮箱
+ * @param sendNick : 发送人昵称
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param files[] : 附件
+ */
+ @SuppressWarnings("null")
+ public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) {
+ JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender();
+ try {
+ MimeMessage mimeMessage = javaMailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ // 设置收件人抄送的名片和地址(相当于群发了)
+ //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>"));
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ // 群发
+ //MimeMessage[] mailMessages = { mimeMessage };
+
+ javaMailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ logger.info("{}", e);
+ }
+ return false;
+ }
+
+ /**
+ * 发送邮件 (完整版) (纯JavaMail)
+ *
+ * @param toAddress : 收件人邮箱
+ * @param mailSubject : 邮件主题
+ * @param mailBody : 邮件正文
+ * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式
+ * @param inLineFile : 内嵌文件
+ * @param files[] : 附件
+ */
+ public static boolean sendMail (String toAddress, String mailSubject, String mailBody,
+ boolean mailBodyIsHtml, File[] attachments){
+ try {
+ // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等 )
+ JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+ mailSender.setHost(host); // 设置邮件服务主机
+ mailSender.setUsername(username); // 发送者邮箱的用户名
+ mailSender.setPassword(password); // 发送者邮箱的密码
+
+ //配置文件,用于实例化java.mail.session
+ Properties pro = System.getProperties();
+ pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权)
+ pro.put("mail.smtp.socketFactory.port", port);
+ pro.put("mail.smtp.socketFactory.fallback", "false");
+ mailSender.setJavaMailProperties(pro);
+
+ //创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage)
+ MimeMessage mimeMessage = mailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8");
+
+ helper.setFrom(sendFrom, sendNick);
+ helper.setTo(toAddress);
+
+ helper.setSubject(mailSubject);
+ helper.setText(mailBody, mailBodyIsHtml);
+
+ // 添加内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源
+ //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile);
+
+ // 添加附件
+ if (ArrayUtils.isNotEmpty(attachments)) {
+ for (File file : attachments) {
+ helper.addAttachment(MimeUtility.encodeText(file.getName()), file);
+ }
+ }
+
+ mailSender.send(mimeMessage);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ static int total = 0;
+ public static void main(String[] args) {
+
+ ExecutorService exec = Executors.newCachedThreadPool();
+ for (int i = 0; i < 20; i++) {
+ exec.execute(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ while(total < 10){
+ String mailBody = "新书快递通知
你的新书快递申请已推送新书,请到空间"
+ + "中查看";
+
+ sendMail("ovono802302@163.com", "测试邮件", mailBody, false, null);
+ System.out.println(total);
+ total++;
+ }
+ }
+ }));
+ }
+ }
+
+}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
index 8e522f9..9b59cf5 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/LocalNomalJobBean.java
@@ -19,6 +19,7 @@
import com.xxl.job.client.util.JacksonUtil;
import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.thread.JobMonitorHelper;
import com.xxl.job.core.util.DynamicSchedulerUtil;
/**
@@ -81,6 +82,7 @@
// update trigger info
DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog);
DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog);
+ JobMonitorHelper.monitor(jobLog.getId());
logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
}
diff --git a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
index 7ca28fc..c15aa2c 100644
--- a/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
+++ b/xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java
@@ -18,6 +18,7 @@
import com.xxl.job.client.util.JacksonUtil;
import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.model.XxlJobLog;
+import com.xxl.job.core.thread.JobMonitorHelper;
import com.xxl.job.core.util.DynamicSchedulerUtil;
import com.xxl.job.core.util.PropertiesUtil;
@@ -85,6 +86,7 @@
// update trigger info
DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog);
+ JobMonitorHelper.monitor(jobLog.getId());
logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
}
diff --git a/xxl-job-admin/src/main/resources/config.properties b/xxl-job-admin/src/main/resources/config.properties
index c22c950..574549d 100644
--- a/xxl-job-admin/src/main/resources/config.properties
+++ b/xxl-job-admin/src/main/resources/config.properties
@@ -1 +1,10 @@
-trigger_log_url=http://localhost:8080/joblog/save
\ No newline at end of file
+# for trigger log callback
+trigger_log_url=http://localhost:8080/joblog/save
+
+# for email
+mail.host=smtp.163.com
+mail.port=25
+mail.username=ovono802302@163.com
+mail.password=asdfzxcv
+mail.sendFrom=ovono802302@163.com
+mail.sendNick=《任务调度中心xxl-job》
\ No newline at end of file
diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml
index 4f16544..2107680 100644
--- a/xxl-job-admin/src/main/resources/springmvc-context.xml
+++ b/xxl-job-admin/src/main/resources/springmvc-context.xml
@@ -38,7 +38,7 @@
-
+
\ No newline at end of file