Unverified 提交 d0f5c1f6 authored 作者: 许雪里's avatar 许雪里 提交者: GitHub

Merge branch 'master' into master

...@@ -408,6 +408,24 @@ XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅 ...@@ -408,6 +408,24 @@ XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅
- 287、F5未来商店 - 287、F5未来商店
- 288、深圳环阳通信息技术有限公司 - 288、深圳环阳通信息技术有限公司
- 289、遠傳電信 - 289、遠傳電信
- 290、作业帮(北京)教育科技有限公司【作业帮】
- 291、成都科鸿智信科技有限公司
- 292、北京木屋时代科技有限公司
- 293、大学通(哈尔滨)科技有限责任公司
- 294、浙江华坤道威数据科技有限公司
- 295、吉祥航空【吉祥航空】
- 296、南京圆周网络科技有限公司
- 297、广州市洋葱omall电子商务
- 298、天津联物科技有限公司
- 299、跑哪儿科技(北京)有限公司
- 300、深圳市美西西餐饮有限公司(喜茶)
- 301、平安不动产有限公司【平安】
- 302、江苏中海昇物联科技有限公司
- 303、湖南牙医帮科技有限公司
- 304、重庆民航凯亚信息技术有限公司(易通航)
- 305、递易(上海)智能科技有限公司
- 306、亚朵
- 307、浙江新课堂教育股份有限公司
- …… - ……
> 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。 > 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。
......
差异被折叠。
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
CREATE database if NOT EXISTS `xxl_job` default character set utf8mb4 collate utf8mb4_unicode_ci; CREATE database if NOT EXISTS `xxl_job` default character set utf8mb4 collate utf8mb4_unicode_ci;
use `xxl_job`; use `xxl_job`;
SET NAMES utf8mb4;
CREATE TABLE `xxl_job_info` ( CREATE TABLE `xxl_job_info` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
......
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>2.2.0-SNAPSHOT</version> <version>2.2.0-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
<description>A distributed task scheduling framework.</description> <description>A distributed task scheduling framework.</description>
<url>https://www.xuxueli.com/</url> <url>https://www.xuxueli.com/</url>
<modules> <modules>
<module>xxl-job-core</module> <module>xxl-job-core</module>
<module>xxl-job-admin</module> <module>xxl-job-admin</module>
<module>xxl-job-executor-samples</module> <module>xxl-job-executor-samples</module>
</modules> </modules>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<maven.test.skip>true</maven.test.skip> <maven.test.skip>true</maven.test.skip>
<xxl-rpc.version>1.5.0</xxl-rpc.version> <xxl-rpc.version>1.5.0</xxl-rpc.version>
<spring.version>4.3.25.RELEASE</spring.version> <spring.version>5.2.5.RELEASE</spring.version>
<spring-boot.version>1.5.22.RELEASE</spring-boot.version> <spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<mybatis-spring-boot-starter.version>1.3.5</mybatis-spring-boot-starter.version>
<mysql-connector-java.version>5.1.48</mysql-connector-java.version> <mybatis-spring-boot-starter.version>2.1.2</mybatis-spring-boot-starter.version>
<mysql-connector-java.version>8.0.19</mysql-connector-java.version>
<slf4j-api.version>1.7.29</slf4j-api.version>
<junit.version>4.12</junit.version> <slf4j-api.version>1.7.30</slf4j-api.version>
<junit.version>4.13</junit.version>
<groovy.version>2.5.8</groovy.version>
<groovy.version>3.0.2</groovy.version>
<maven-source-plugin.version>3.2.0</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version> <maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version> <maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
<maven-war-plugin.version>3.2.3</maven-war-plugin.version> <maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
</properties> <maven-war-plugin.version>3.2.3</maven-war-plugin.version>
</properties>
<build>
<plugins> <build>
</plugins> <plugins>
</build> </plugins>
</build>
<licenses>
<license> <licenses>
<name>GNU General Public License version 3</name> <license>
<url>https://opensource.org/licenses/GPL-3.0</url> <name>GNU General Public License version 3</name>
</license> <url>https://opensource.org/licenses/GPL-3.0</url>
</licenses> </license>
</licenses>
<scm>
<tag>master</tag> <scm>
<url>https://github.com/xuxueli/xxl-job.git</url> <tag>master</tag>
<connection>scm:git:https://github.com/xuxueli/xxl-job.git</connection> <url>https://github.com/xuxueli/xxl-job.git</url>
<developerConnection>scm:git:git@github.com:xuxueli/xxl-job.git</developerConnection> <connection>scm:git:https://github.com/xuxueli/xxl-job.git</connection>
</scm> <developerConnection>scm:git:git@github.com:xuxueli/xxl-job.git</developerConnection>
<developers> </scm>
<developer> <developers>
<id>XXL</id> <developer>
<name>xuxueli</name> <id>XXL</id>
<email>931591021@qq.com</email> <name>xuxueli</name>
<url>https://github.com/xuxueli</url> <email>931591021@qq.com</email>
</developer> <url>https://github.com/xuxueli</url>
</developers> </developer>
</developers>
<profiles>
<profiles>
<profile>
<id>release</id> <profile>
<build> <id>release</id>
<plugins> <build>
<!-- Source --> <plugins>
<plugin> <!-- Source -->
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-source-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>${maven-source-plugin.version}</version> <artifactId>maven-source-plugin</artifactId>
<executions> <version>${maven-source-plugin.version}</version>
<execution> <executions>
<phase>package</phase> <execution>
<goals> <phase>package</phase>
<goal>jar-no-fork</goal> <goals>
</goals> <goal>jar-no-fork</goal>
</execution> </goals>
</executions> </execution>
</plugin> </executions>
<!-- Javadoc --> </plugin>
<plugin> <!-- Javadoc -->
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-javadoc-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>${maven-javadoc-plugin.version}</version> <artifactId>maven-javadoc-plugin</artifactId>
<executions> <version>${maven-javadoc-plugin.version}</version>
<execution> <executions>
<phase>package</phase> <execution>
<goals> <phase>package</phase>
<goal>jar</goal> <goals>
</goals> <goal>jar</goal>
<configuration> </goals>
<doclint>none</doclint> <configuration>
</configuration> <doclint>none</doclint>
</execution> </configuration>
</executions> </execution>
</plugin> </executions>
<!-- GPG --> </plugin>
<plugin> <!-- GPG -->
<groupId>org.apache.maven.plugins</groupId> <plugin>
<artifactId>maven-gpg-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<version>${maven-gpg-plugin.version}</version> <artifactId>maven-gpg-plugin</artifactId>
<configuration> <version>${maven-gpg-plugin.version}</version>
<useAgent>false</useAgent> <configuration>
</configuration> <useAgent>false</useAgent>
<executions> </configuration>
<execution> <executions>
<phase>verify</phase> <execution>
<goals> <phase>verify</phase>
<goal>sign</goal> <goals>
</goals> <goal>sign</goal>
</execution> </goals>
</executions> </execution>
</plugin> </executions>
</plugins> </plugin>
</build> </plugins>
<distributionManagement> </build>
<snapshotRepository> <distributionManagement>
<id>oss</id> <snapshotRepository>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url> <id>oss</id>
</snapshotRepository> <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<repository> </snapshotRepository>
<id>oss</id> <repository>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> <id>oss</id>
</repository> <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</distributionManagement> </repository>
</profile> </distributionManagement>
</profiles> </profile>
</profiles>
</project> </project>
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>2.2.0-SNAPSHOT</version> <version>2.2.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-admin</artifactId> <artifactId>xxl-job-admin</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>${spring-boot.version}</version> <version>${spring-boot.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
<dependencies> <dependencies>
<!-- starter-web:spring-webmvc + autoconfigure + logback + yaml + tomcat --> <!-- starter-web:spring-webmvc + autoconfigure + logback + yaml + tomcat -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<!-- starter-test:junit + spring-test + mockito --> <!-- starter-test:junit + spring-test + mockito -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- freemarker-starter --> <!-- freemarker-starter -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId> <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency> </dependency>
<!-- mail-starter --> <!-- mail-starter -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId> <artifactId>spring-boot-starter-mail</artifactId>
</dependency> </dependency>
<!-- starter-actuator --> <!-- starter-actuator -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<!-- mybatis-starter:mybatis + mybatis-spring + tomcat-jdbc(default) --> <!-- mybatis-starter:mybatis + mybatis-spring + hikari(default) -->
<dependency> <dependency>
<groupId>org.mybatis.spring.boot</groupId> <groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId> <artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version> <version>${mybatis-spring-boot-starter.version}</version>
</dependency> </dependency>
<!-- mysql --> <!-- mysql -->
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version> <version>${mysql-connector-java.version}</version>
</dependency> </dependency>
<!-- xxl-job-core --> <!-- xxl-job-core -->
<dependency> <dependency>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId> <artifactId>xxl-job-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version> <version>${spring-boot.version}</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
<goal>repackage</goal> <goal>repackage</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<!-- docker --> <!-- docker -->
<plugin> <plugin>
<groupId>com.spotify</groupId> <groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId> <artifactId>docker-maven-plugin</artifactId>
<version>0.4.13</version> <version>0.4.13</version>
<configuration> <configuration>
<!-- made of '[a-z0-9-_.]' --> <!-- made of '[a-z0-9-_.]' -->
<imageName>${project.artifactId}:${project.version}</imageName> <imageName>${project.artifactId}:${project.version}</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory> <dockerDirectory>${project.basedir}</dockerDirectory>
<resources> <resources>
<resource> <resource>
<targetPath>/</targetPath> <targetPath>/</targetPath>
<directory>${project.build.directory}</directory> <directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include> <include>${project.build.finalName}.jar</include>
</resource> </resource>
</resources> </resources>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>
package com.xxl.job.admin.core.alarm;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
/**
* @author xuxueli 2020-01-19
*/
public interface JobAlarm {
/**
* job alarm
*
* @param info
* @param jobLog
* @return
*/
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog);
}
package com.xxl.job.admin.core.alarm;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class JobAlarmer implements ApplicationContextAware, InitializingBean {
private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class);
private ApplicationContext applicationContext;
private List<JobAlarm> jobAlarmList;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
Map<String, JobAlarm> serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class);
if (serviceBeanMap != null && serviceBeanMap.size() > 0) {
jobAlarmList = new ArrayList<JobAlarm>(serviceBeanMap.values());
}
}
/**
* job alarm
*
* @param info
* @param jobLog
* @return
*/
public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) {
boolean result = false;
if (jobAlarmList!=null && jobAlarmList.size()>0) {
result = true; // success means all-success
for (JobAlarm alarm: jobAlarmList) {
boolean resultItem = false;
try {
resultItem = alarm.doAlarm(info, jobLog);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
if (!resultItem) {
result = false;
}
}
}
return result;
}
}
package com.xxl.job.admin.core.alarm.impl;
import com.xxl.job.admin.core.alarm.JobAlarm;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import javax.mail.internet.MimeMessage;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* job alarm by email
*
* @author xuxueli 2020-01-19
*/
@Component
public class EmailJobAlarm implements JobAlarm {
private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class);
/**
* fail alarm
*
* @param jobLog
*/
public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog){
boolean alarmResult = true;
// send monitor email
if (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) {
// alarmContent
String alarmContent = "Alarm Job LogId=" + jobLog.getId();
if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) {
alarmContent += "<br>TriggerMsg=<br>" + jobLog.getTriggerMsg();
}
if (jobLog.getHandleCode()>0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) {
alarmContent += "<br>HandleCode=" + jobLog.getHandleMsg();
}
// email info
XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup()));
String personal = I18nUtil.getString("admin_name_full");
String title = I18nUtil.getString("jobconf_monitor");
String content = MessageFormat.format(loadEmailJobAlarmTemplate(),
group!=null?group.getTitle():"null",
info.getId(),
info.getJobDesc(),
alarmContent);
Set<String> emailSet = new HashSet<String>(Arrays.asList(info.getAlarmEmail().split(",")));
for (String email: emailSet) {
// make mail
try {
MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailUserName(), personal);
helper.setTo(email);
helper.setSubject(title);
helper.setText(content, true);
XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage);
} catch (Exception e) {
logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e);
alarmResult = false;
}
}
}
return alarmResult;
}
/**
* load email job alarm template
*
* @return
*/
private static final String loadEmailJobAlarmTemplate(){
String mailBodyTemplate = "<h5>" + I18nUtil.getString("jobconf_monitor_detail") + ":</span>" +
"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +
" <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
" <tr>\n" +
" <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobgroup") +"</td>\n" +
" <td width=\"10%\" >"+ I18nUtil.getString("jobinfo_field_id") +"</td>\n" +
" <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobdesc") +"</td>\n" +
" <td width=\"10%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_title") +"</td>\n" +
" <td width=\"40%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_content") +"</td>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr>\n" +
" <td>{0}</td>\n" +
" <td>{1}</td>\n" +
" <td>{2}</td>\n" +
" <td>"+ I18nUtil.getString("jobconf_monitor_alarm_type") +"</td>\n" +
" <td>{3}</td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>";
return mailBodyTemplate;
}
}
package com.xxl.job.admin.core.conf; package com.xxl.job.admin.core.conf;
import com.xxl.job.admin.core.alarm.JobAlarmer;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler; import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.dao.*; import com.xxl.job.admin.dao.*;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
...@@ -10,6 +11,7 @@ import org.springframework.stereotype.Component; ...@@ -10,6 +11,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.util.Arrays;
/** /**
* xxl-job config * xxl-job config
...@@ -81,9 +83,14 @@ public class XxlJobAdminConfig implements InitializingBean, DisposableBean { ...@@ -81,9 +83,14 @@ public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
private JavaMailSender mailSender; private JavaMailSender mailSender;
@Resource @Resource
private DataSource dataSource; private DataSource dataSource;
@Resource
private JobAlarmer jobAlarmer;
public String getI18n() { public String getI18n() {
if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) {
return "zh_CN";
}
return i18n; return i18n;
} }
...@@ -144,4 +151,8 @@ public class XxlJobAdminConfig implements InitializingBean, DisposableBean { ...@@ -144,4 +151,8 @@ public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
return dataSource; return dataSource;
} }
public JobAlarmer getJobAlarmer() {
return jobAlarmer;
}
} }
package com.xxl.job.admin.core.thread; package com.xxl.job.admin.core.thread;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig; import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.trigger.TriggerTypeEnum; import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
import com.xxl.job.admin.core.util.I18nUtil; import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.model.ReturnT;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.MimeMessageHelper;
import javax.mail.internet.MimeMessage;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
...@@ -69,13 +61,7 @@ public class JobFailMonitorHelper { ...@@ -69,13 +61,7 @@ public class JobFailMonitorHelper {
// 2、fail alarm monitor // 2、fail alarm monitor
int newAlarmStatus = 0; // 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败 int newAlarmStatus = 0; // 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败
if (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) { if (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) {
boolean alarmResult = true; boolean alarmResult = XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log);
try {
alarmResult = failAlarm(info, log);
} catch (Exception e) {
alarmResult = false;
logger.error(e.getMessage(), e);
}
newAlarmStatus = alarmResult?2:3; newAlarmStatus = alarmResult?2:3;
} else { } else {
newAlarmStatus = 1; newAlarmStatus = 1;
...@@ -121,89 +107,4 @@ public class JobFailMonitorHelper { ...@@ -121,89 +107,4 @@ public class JobFailMonitorHelper {
} }
} }
// ---------------------- alarm ----------------------
// email alarm template
private static final String mailBodyTemplate = "<h5>" + I18nUtil.getString("jobconf_monitor_detail") + ":</span>" +
"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +
" <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
" <tr>\n" +
" <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobgroup") +"</td>\n" +
" <td width=\"10%\" >"+ I18nUtil.getString("jobinfo_field_id") +"</td>\n" +
" <td width=\"20%\" >"+ I18nUtil.getString("jobinfo_field_jobdesc") +"</td>\n" +
" <td width=\"10%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_title") +"</td>\n" +
" <td width=\"40%\" >"+ I18nUtil.getString("jobconf_monitor_alarm_content") +"</td>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr>\n" +
" <td>{0}</td>\n" +
" <td>{1}</td>\n" +
" <td>{2}</td>\n" +
" <td>"+ I18nUtil.getString("jobconf_monitor_alarm_type") +"</td>\n" +
" <td>{3}</td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>";
/**
* fail alarm
*
* @param jobLog
*/
private boolean failAlarm(XxlJobInfo info, XxlJobLog jobLog){
boolean alarmResult = true;
// send monitor email
if (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) {
// alarmContent
String alarmContent = "Alarm Job LogId=" + jobLog.getId();
if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) {
alarmContent += "<br>TriggerMsg=<br>" + jobLog.getTriggerMsg();
}
if (jobLog.getHandleCode()>0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) {
alarmContent += "<br>HandleCode=" + jobLog.getHandleMsg();
}
// email info
XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup()));
String personal = I18nUtil.getString("admin_name_full");
String title = I18nUtil.getString("jobconf_monitor");
String content = MessageFormat.format(mailBodyTemplate,
group!=null?group.getTitle():"null",
info.getId(),
info.getJobDesc(),
alarmContent);
Set<String> emailSet = new HashSet<String>(Arrays.asList(info.getAlarmEmail().split(",")));
for (String email: emailSet) {
// make mail
try {
MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailUserName(), personal);
helper.setTo(email);
helper.setSubject(title);
helper.setText(content, true);
XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage);
} catch (Exception e) {
logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e);
alarmResult = false;
}
}
}
// do something, custom alarm strategy, such as sms
return alarmResult;
}
} }
...@@ -30,8 +30,7 @@ public class I18nUtil { ...@@ -30,8 +30,7 @@ public class I18nUtil {
try { try {
// build i18n prop // build i18n prop
String i18n = XxlJobAdminConfig.getAdminConfig().getI18n(); String i18n = XxlJobAdminConfig.getAdminConfig().getI18n();
i18n = (i18n!=null && i18n.trim().length()>0)?("_"+i18n):i18n; String i18nFile = MessageFormat.format("i18n/message_{0}.properties", i18n);
String i18nFile = MessageFormat.format("i18n/message{0}.properties", i18n);
// load prop // load prop
Resource resource = new ClassPathResource(i18nFile); Resource resource = new ClassPathResource(i18nFile);
......
### web ### web
server.port=8080 server.port=8080
server.context-path=/xxl-job-admin server.servlet.context-path=/xxl-job-admin
### actuator ### actuator
management.context-path=/actuator management.server.servlet.context-path=/actuator
management.health.mail.enabled=false management.health.mail.enabled=false
### resources ### resources
...@@ -20,6 +20,7 @@ spring.freemarker.settings.number_format=0.########## ...@@ -20,6 +20,7 @@ spring.freemarker.settings.number_format=0.##########
### mybatis ### mybatis
mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml
#mybatis.type-aliases-package=com.xxl.job.admin.core.model
### xxl-job, datasource ### xxl-job, datasource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8
...@@ -27,14 +28,18 @@ spring.datasource.username=root ...@@ -27,14 +28,18 @@ spring.datasource.username=root
spring.datasource.password=root_pwd spring.datasource.password=root_pwd
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource ### datasource-pool
spring.datasource.tomcat.max-wait=10000 spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.tomcat.max-active=30 spring.datasource.hikari.minimum-idle=10
spring.datasource.tomcat.test-on-borrow=true spring.datasource.hikari.maximum-pool-size=30
spring.datasource.tomcat.validation-query=SELECT 1 spring.datasource.hikari.auto-commit=true
spring.datasource.tomcat.validation-interval=30000 spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=HikariCP
### xxl-job email spring.datasource.hikari.max-lifetime=900000
spring.datasource.hikari.connection-timeout=10000
spring.datasource.hikari.connection-test-query=SELECT 1
### xxl-job, email
spring.mail.host=smtp.qq.com spring.mail.host=smtp.qq.com
spring.mail.port=25 spring.mail.port=25
spring.mail.username=xxx@qq.com spring.mail.username=xxx@qq.com
...@@ -47,8 +52,8 @@ spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFact ...@@ -47,8 +52,8 @@ spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFact
### xxl-job, access token ### xxl-job, access token
xxl.job.accessToken= xxl.job.accessToken=
### xxl-job, i18n (default empty as chinese, "en" as english) ### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")
xxl.job.i18n= xxl.job.i18n=zh_CN
## xxl-job, triggerpool max size ## xxl-job, triggerpool max size
xxl.job.triggerpool.fast.max=200 xxl.job.triggerpool.fast.max=200
......
admin_name=任務調度中心
admin_name_full=分布式任務調度平臺XXL-JOB
admin_version=2.1.1
admin_i18n=
## system
system_tips=系統提示
system_ok=確定
system_close=關閉
system_save=儲存
system_cancel=取消
system_search=搜尋
system_status=狀態
system_opt=操作
system_please_input=請輸入
system_please_choose=请選擇
system_success=成功
system_fail=失敗
system_add_suc=新增成功
system_add_fail=新增失敗
system_update_suc=更新成功
system_update_fail=更新失敗
system_all=全部
system_api_error=API錯誤
system_show=查看
system_empty=
system_opt_suc=操作成功
system_opt_fail=操作失敗
system_opt_edit=編輯
system_opt_del=刪除
system_unvalid=非法
system_not_found=不存在
system_nav=導航
system_digits=整數
system_lengh_limit=長度限制
system_permission_limit=權限控管
system_welcome=歡迎
## daterangepicker
daterangepicker_ranges_recent_hour=最近一小時
daterangepicker_ranges_today=今日
daterangepicker_ranges_yesterday=昨日
daterangepicker_ranges_this_month=本月
daterangepicker_ranges_last_month=上個月
daterangepicker_ranges_recent_week=最近一周
daterangepicker_ranges_recent_month=最近一月
daterangepicker_custom_name=自定義
daterangepicker_custom_starttime=起始時間
daterangepicker_custom_endtime=結束時間
daterangepicker_custom_daysofweek=日,一,二,三,四,五,六
daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月
## dataTable
dataTable_sProcessing=處理中...
dataTable_sLengthMenu=每頁 _MENU_ 條記錄
dataTable_sZeroRecords=沒有相符合記錄
dataTable_sInfo=第 _PAGE_ 頁 ( 總共 _PAGES_ 頁,_TOTAL_ 條記錄 )
dataTable_sInfoEmpty=無記錄
dataTable_sInfoFiltered=(由 _MAX_ 項結果過濾)
dataTable_sSearch=搜尋
dataTable_sEmptyTable=表中資料為空
dataTable_sLoadingRecords=載入中...
dataTable_sFirst=首頁
dataTable_sPrevious=上頁
dataTable_sNext=下頁
dataTable_sLast=末頁
dataTable_sSortAscending=: 以升幂排序此列
dataTable_sSortDescending=: 以降幂排序此列
## login
login_btn=登入
login_remember_me=記住密碼
login_username_placeholder=請輸入登入帳號
login_password_placeholder=請輸入登入密碼
login_username_empty=請輸入登入帳號
login_username_lt_4=登入帳號不應低於4位數
login_password_empty=請輸入登入密碼
login_password_lt_4=登入密碼不應低於4位數
login_success=登入成功
login_fail=登入失敗
login_param_empty=帳號或密碼為空值
login_param_unvalid=帳號或密碼錯誤
## logout
logout_btn=登出
logout_confirm=確認登出?
logout_success=登出成功
logout_fail=登出失敗
## change pwd
change_pwd=修改密碼
change_pwd_suc_to_logout=修改密碼成功,即將登出
change_pwd_field_newpwd=新密碼
## dashboard
job_dashboard_name=運行報表
job_dashboard_job_num=任務數量
job_dashboard_job_num_tip=調度中心運行的任務數量
job_dashboard_trigger_num=調度次數
job_dashboard_trigger_num_tip=調度中心觸發的調度次數
job_dashboard_jobgroup_num=執行器數量
job_dashboard_jobgroup_num_tip=調度中心在線的執行器機器數量
job_dashboard_report=調度報表
job_dashboard_report_loaddata_fail=調度報表資料加載異常
job_dashboard_date_report=日期分布圖
job_dashboard_rate_report=成功比例圖
## job info
jobinfo_name=任務管理
jobinfo_job=任務
jobinfo_field_add=新增
jobinfo_field_update=更新任務
jobinfo_field_id=任務ID
jobinfo_field_jobgroup=執行器
jobinfo_field_jobdesc=任務描述
jobinfo_field_gluetype=運行模式
jobinfo_field_executorparam=任務參數
jobinfo_field_cron_unvalid=Cron 格式非法
jobinfo_field_cron_never_fire=Cron 格式非法,永遠不會觸發
jobinfo_field_author=負責人
jobinfo_field_timeout=任務超時秒數
jobinfo_field_alarmemail=告警郵件
jobinfo_field_alarmemail_placeholder=輸入多個告警郵件地址,請以逗號分隔
jobinfo_field_executorRouteStrategy=路由策略
jobinfo_field_childJobId=子任務ID
jobinfo_field_childJobId_placeholder=輸入子任務ID,如有多個請以逗號分隔
jobinfo_field_executorBlockStrategy=阻塞處理策略
jobinfo_field_executorFailRetryCount=失敗重試次數
jobinfo_field_executorFailRetryCount_placeholder=失敗重試次數,大於零時生效
jobinfo_script_location=腳本位置
jobinfo_shard_index=分片序號
jobinfo_shard_total=分片總數
jobinfo_opt_stop=停止
jobinfo_opt_start=啟動
jobinfo_opt_log=查詢日誌
jobinfo_opt_run=執行一次
jobinfo_opt_registryinfo=注冊節點
jobinfo_opt_next_time=下次執行時間
jobinfo_glue_remark=源碼備註
jobinfo_glue_remark_limit=源碼備註長度限制為4~100
jobinfo_glue_rollback=版本回復
jobinfo_glue_jobid_unvalid=任務ID非法
jobinfo_glue_gluetype_unvalid=該任務非GLUE模式
jobinfo_field_executorTimeout_placeholder=任務超時時間,單位秒,大於零時生效
## job log
joblog_name=調度日誌
joblog_status=狀態
joblog_status_all=全部
joblog_status_suc=成功
joblog_status_fail=失敗
joblog_status_running=進行中
joblog_field_triggerTime=調度時間
joblog_field_triggerCode=調度結果
joblog_field_triggerMsg=調度備註
joblog_field_handleTime=執行時間
joblog_field_handleCode=執行结果
joblog_field_handleMsg=執行備註
joblog_field_executorAddress=執行器地址
joblog_clean=清理
joblog_clean_log=日誌清理
joblog_clean_type=清理方式
joblog_clean_type_1=清理一個月之前日誌資料
joblog_clean_type_2=清理三個月之前日誌資料
joblog_clean_type_3=清理六個月之前日誌資料
joblog_clean_type_4=清理一年之前日誌資料
joblog_clean_type_5=清理一千條以前日誌資料
joblog_clean_type_6=清理一萬條以前日誌資料
joblog_clean_type_7=清理三萬條以前日誌資料
joblog_clean_type_8=清理十萬條以前日誌資料
joblog_clean_type_9=清理所有日誌資料
joblog_clean_type_unvalid=清理類型參数異常
joblog_handleCode_200=成功
joblog_handleCode_500=失敗
joblog_handleCode_502=失敗(超時)
joblog_kill_log=终止任務
joblog_kill_log_limit=調度失敗,無法终止日誌
joblog_kill_log_byman=人為操作主動終止
joblog_rolling_log=執行日誌
joblog_rolling_log_refresh=更新
joblog_rolling_log_triggerfail=任務發起調度失敗,無法查看執行日誌
joblog_rolling_log_failoften=終止請求Rolling日誌,請求失敗次數超上限,可刷新頁面重新加載日誌
joblog_logid_unvalid=日誌ID非法
## job group
jobgroup_name=執行器管理
jobgroup_list=執行器列表
jobgroup_add=新增執行器
jobgroup_edit=編輯執行器
jobgroup_del=刪除執行器
jobgroup_field_order=排序
jobgroup_field_title=名稱
jobgroup_field_addressType=注冊方式
jobgroup_field_addressType_0=自動注冊
jobgroup_field_addressType_1=手動登錄
jobgroup_field_addressType_limit=手動登錄注冊方式,機器地址不可為空
jobgroup_field_registryList=機器地址
jobgroup_field_registryList_unvalid=機器地址格式非法
jobgroup_field_registryList_placeholder=請輸入執行器地址列表,多個地址請以逗號分隔
jobgroup_field_appName_limit=限制以小寫字母開頭,由小寫字母、數字和中划線組成
jobgroup_field_appName_length=AppName長度限制為4~64
jobgroup_field_title_length=名稱長度限制為4~12
jobgroup_field_order_digits=請輸入整數
jobgroup_field_orderrange=取值範圍為1~1000
jobgroup_del_limit_0=拒絕刪除,該執行器使用中
jobgroup_del_limit_1=拒絕删除,系统至少保留一個執行器
jobgroup_empty=不存在有效執行器,請聯絡系統管理員
## job conf
jobconf_block_SERIAL_EXECUTION=單機串行
jobconf_block_DISCARD_LATER=丢棄后續調度
jobconf_block_COVER_EARLY=覆蓋之前調度
jobconf_route_first=第一個
jobconf_route_last=最後一個
jobconf_route_round=輪詢
jobconf_route_random=隨機
jobconf_route_consistenthash=一致性HASH
jobconf_route_lfu=最不經常使用
jobconf_route_lru=最近最久未使用
jobconf_route_failover=故障轉移
jobconf_route_busyover=忙碌轉移
jobconf_route_shard=分片廣播
jobconf_idleBeat=空閒檢測
jobconf_beat=心跳檢測
jobconf_monitor=任務調度中心監控告警
jobconf_monitor_detail=監控告警明细
jobconf_monitor_alarm_title=告警類型
jobconf_monitor_alarm_type=調度失敗
jobconf_monitor_alarm_content=告警内容
jobconf_trigger_admin_adress=調度機器
jobconf_trigger_exe_regtype=執行器-注冊方式
jobconf_trigger_exe_regaddress=執行器-地址列表
jobconf_trigger_address_empty=調度失敗:執行器地址為空
jobconf_trigger_run=觸發調度
jobconf_trigger_child_run=觸發子任務
jobconf_callback_child_msg1={0}/{1} [任務ID={2}], 觸發{3}, 觸發備註: {4} <br>
jobconf_callback_child_msg2={0}/{1} [任務ID={2}], 觸發失败, 觸發備註: 任務ID格式錯誤 <br>
jobconf_trigger_type=任務觸發類型
jobconf_trigger_type_cron=Cron觸發
jobconf_trigger_type_manual=手動觸發
jobconf_trigger_type_parent=父任務觸發
jobconf_trigger_type_api=API觸發
jobconf_trigger_type_retry=失敗重試觸發
## user
user_manage=用户管理
user_username=帳號
user_password=密碼
user_role=角色
user_role_admin=管理員
user_role_normal=普通用戶
user_permission=權限
user_add=新增用戶
user_update=更新用戶
user_username_repeat=帳號重複
user_username_valid=限制以小寫字母開頭,由小寫字母、數字組成
user_password_update_placeholder=請輸入新密碼,為空則不更新密碼
user_update_loginuser_limit=禁止操作當前登入帳號
## help
job_help=使用教程
job_help_document=官方文件
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论