From 1e0ae9e5731b7f8536c55596d614714b9dbca669 Mon Sep 17 00:00:00 2001 From: "xueli.xue" Date: Sat, 12 Mar 2016 16:12:07 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E5=BA=A6=E5=A4=B1=E8=B4=A5=E9=82=AE?= =?UTF-8?q?=E4=BB=B6=E6=8A=A5=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xxl-job-admin/pom.xml | 7 + .../resolver/WebExceptionResolver.java | 2 +- .../xxl/job/core/thread/JobMonitorHelper.java | 82 ++++++++ .../job/core/util/DynamicSchedulerUtil.java | 1 + .../java/com/xxl/job/core/util/MailUtil.java | 181 ++++++++++++++++++ .../job/service/job/LocalNomalJobBean.java | 2 + .../job/service/job/RemoteHttpJobBean.java | 2 + .../src/main/resources/config.properties | 11 +- .../src/main/resources/springmvc-context.xml | 3 +- 9 files changed, 287 insertions(+), 4 deletions(-) rename xxl-job-admin/src/main/java/com/xxl/job/{core => controller}/resolver/WebExceptionResolver.java (94%) create mode 100644 xxl-job-admin/src/main/java/com/xxl/job/core/thread/JobMonitorHelper.java create mode 100644 xxl-job-admin/src/main/java/com/xxl/job/core/util/MailUtil.java diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index bfa25fe9..192e6e64 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/core/resolver/WebExceptionResolver.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java similarity index 94% rename from xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java rename to xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java index 3bc58d7f..9060e28c 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/resolver/WebExceptionResolver.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/resolver/WebExceptionResolver.java @@ -1,4 +1,4 @@ -package com.xxl.job.core.resolver; +package com.xxl.job.controller.resolver; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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 00000000..c322d9c4 --- /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 1b06f653..ef675c72 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 @@ public final class DynamicSchedulerUtil implements ApplicationContextAware, Init } // 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 00000000..ff2204d5 --- /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 8e522f92..9b59cf5c 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.HttpUtil; 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 @@ public abstract class LocalNomalJobBean extends QuartzJobBean { // 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 7ca28fcf..c15aa2c4 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.HttpUtil; 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 @@ public class RemoteHttpJobBean extends QuartzJobBean { // 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 c22c950d..574549dc 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 4f165449..21076803 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