提交 3fda5448 authored 作者: Mrwb's avatar Mrwb 提交者: GitHub

Merge pull request #1 from xuxueli/master

update from origin
Please answer some questions before submitting your issue. Thanks!
### Which version of XXL-JOB do you using?
### Expected behavior
### Actual behavior
### Steps to reproduce the behavior
### Other information
\ No newline at end of file
**What kind of change does this PR introduce?** (check at least one)
- [ ] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:
**The description of the PR:**
**Other information:**
\ No newline at end of file
# 分布式任务调度平台XXL-JOB
[![Build Status](https://travis-ci.org/xuxueli/xxl-job.svg?branch=master)](https://travis-ci.org/xuxueli/xxl-job)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/)
[![GitHub release](https://img.shields.io/github/release/xuxueli/xxl-job.svg)](https://github.com/xuxueli/xxl-job/releases)
[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0.html)
[![Gitter](https://badges.gitter.im/xuxueli/xxl-job.svg)](https://gitter.im/xuxueli/xxl-job?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
<p align="center">
<a href="http://www.xuxueli.com/">
<img src="https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg" width="150">
</a>
<h3 align="center">XXL-JOB</h3>
<p align="center">
XXL-JOB, a lightweight distributed task scheduling framework.
<br>
<a href="http://www.xuxueli.com/"><strong>-- Browse xuxueli's website. --</strong></a>
<br>
<br>
<a href="https://travis-ci.org/xuxueli/xxl-job">
<img src="https://travis-ci.org/xuxueli/xxl-job.svg?branch=master" >
</a>
<a href="https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/">
<img src="https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/badge.svg" >
</a>
<a href="https://github.com/xuxueli/xxl-job/releases">
<img src="https://img.shields.io/github/release/xuxueli/xxl-job.svg" >
</a>
<a href="http://www.gnu.org/licenses/gpl-3.0.html">
<img src="https://img.shields.io/badge/license-GPLv3-blue.svg" >
</a>
<a href="https://gitter.im/xuxueli/xxl-job?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge">
<img src="https://badges.gitter.im/xuxueli/xxl-job.svg" >
</a>
</p>
</p>
## Intro
XXL-JOB is a lightweight distributed task scheduling framework.
It's core design goal is to develop quickly and learn simple, lightweight, and easy to expand.
Now, it's already open source, and many companies use it in production environments, real "out-of-the-box".
XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
![输入图片说明](https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg "在这里输入图片标题")
### 文档
## Documentation
- [中文文档](https://github.com/xuxueli/xxl-job/blob/master/doc/XXL-JOB官方文档.md)
- [Englis Documentation](https://github.com/xuxueli/xxl-job/blob/master/doc/XXL-JOB-Englis-Documentation.md)
- 官方文档:[XXL-JOB官方文档](https://github.com/xuxueli/xxl-job/blob/master/doc/XXL-JOB官方文档.md)
### 特性
## Features
- 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手;
- 2、动态:支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,即时生效;
- 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现,可保证调度中心HA;
......@@ -41,11 +68,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
- 23、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发对应集群中所有执行器执行一次任务,同时传递分片参数;可根据分片参数开发分片任务;
- 24、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
### 架构图
![输入图片说明](https://static.oschina.net/uploads/img/201707/17190028_aEE2.png "在这里输入图片标题")
### 发展
## Development
于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
于2015-11月,XXL-JOB终于RELEASE了第一个大版本V1.0, 随后我将之发布到OSCHINA,XXL-JOB在OSCHINA上获得了@红薯的热门推荐,同期分别达到了OSCHINA的“热门动弹”排行第一和git.oschina的开源软件月热度排行第一,在此特别感谢红薯,感谢大家的关注和支持。
......@@ -56,7 +80,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
于2017-05-13,在上海举办的 "[第62期开源中国源创会](https://www.oschina.net/event/2236961)" 的 "放码过来" 环节,我登台对XXL-JOB做了演讲,台下五百位在场观众反响热烈([图文回顾](https://www.oschina.net/question/2686220_2242120) )。
#### 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。
** 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。**
据最新统计, 自2016-01-21接入至2017-07-07期间,该系统已调度约60万余次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。
至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止2016-07-19为止,XXL-JOB已接入的公司包括不限于:
......@@ -94,60 +118,43 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
- 31、四川互宜达科技有限公司
- 32、钱包行云(北京)科技有限公司
- 33、重庆欣才集团
- 34、咪咕互动娱乐有限公司(中国移动)
- 35、北京诺亦腾科技有限公司
- 36、增长引擎(北京)信息技术有限公司
- ……
欢迎大家的关注和使用,XXL-JOB也将拥抱变化,持续发展。
### 下载
#### 源码仓库地址 (将会在两个git仓库同步发布最新代码)
源码仓库地址 | Release Download
--- | ---
[https://github.com/xuxueli/xxl-job](https://github.com/xuxueli/xxl-job) | [Download](https://github.com/xuxueli/xxl-job/releases)
[http://git.oschina.net/xuxueli0323/xxl-job](http://git.oschina.net/xuxueli0323/xxl-job) | [Download](http://git.oschina.net/xuxueli0323/xxl-job/releases)
#### 中央仓库地址 (最新Release版本:1.8.0)
```
<!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>1.8.0</version>
</dependency>
```
#### 博客地址 (将会在两个博客同步更新文档)
- [oschina地址](http://my.oschina.net/xuxueli/blog/690978)
- [cnblogs地址](http://www.cnblogs.com/xuxueli/p/5021979.html)
## Communication
#### 技术交流群 (仅作技术交流)
- 腾讯QQ群(6):399758605
- 腾讯QQ群(5):138274130 (群即将满,请加群6)
- 腾讯QQ群(4):464762661 (群即将满,请加群6)
- 腾讯QQ群(3):242151780 (群即将满,请加群6)
- 腾讯QQ群(2):438249535 (群即将满,请加群6)
- 腾讯QQ群(1):367260654 (群即将满,请加群6)
- [Gitter](https://gitter.im/xuxueli/xxl-job)
- 群5:138274130 [![image](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=a3f3aea7e5943e7a24e9726495747ddc19bccd3592d7a70ecb5a97b616062241 )
- 群4:464762661 (群即将满,请加群5)
- 群3:242151780 (群即将满,请加群5)
- 群2:438249535 (群即将满,请加群5)
- 群1:367260654 (群即将满,请加群5)
## Issue
如有问题可在 [Github Issues](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群;
### 报告问题
XXL-JOB托管在Github上,如有问题可在 [ISSUES](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群;
## User Registration
登记仅为了产品推广,产品开源免费。
请接入使用的公司或个人进行用户登记 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 )
### 接入登记(登记仅为了推广,产品开源免费)
更多接入公司,欢迎在github [登记](https://github.com/xuxueli/xxl-job/issues/1 )
### 开源协议
## Copyright and license
产品开源免费,并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。
XXL-JOB采用GPLv3协议,目的是为了保证用户的自由使用权利。协议可避免专利申请的特殊危险 "the GPL assures that patents cannot be used to render the program non-free.(摘自GPLv3)"。
Copyright (c) 2015-present, xuxueli.
---
### 支持的话可以扫一扫,支持 [XXL系列](https://github.com/xuxueli) 的建设:)
## Donate
支持的话可以扫一扫,请作者喝杯咖啡吧:)
微信:![输入图片说明](https://static.oschina.net/uploads/img/201707/07214300_qhxT.png "在这里输入图片标题")
支付宝:![输入图片说明](http://images2015.cnblogs.com/blog/554415/201605/554415-20160513183306234-1939652116.png "在这里输入图片标题")
# 《A lightweight distributed task scheduling framework. "XXL-JOB"》
[![Build Status](https://travis-ci.org/xuxueli/xxl-job.svg?branch=master)](https://travis-ci.org/xuxueli/xxl-job)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/)
[![GitHub release](https://img.shields.io/github/release/xuxueli/xxl-job.svg)](https://github.com/xuxueli/xxl-job/releases)
[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0.html)
[![Gitter](https://badges.gitter.im/xuxueli/xxl-job.svg)](https://gitter.im/xuxueli/xxl-job?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
## 1、Intro
### 1.1 overview
差异被折叠。
......@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version>
<version>1.8.2-SNAPSHOT</version>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
......@@ -17,6 +17,37 @@
<module>xxl-job-executor-springboot-example</module>
</modules>
<properties>
<javax.servlet-api.version>3.0.1</javax.servlet-api.version>
<jsp-api.version>2.2</jsp-api.version>
<spring.version>3.2.18.RELEASE</spring.version>
<jackson-mapper-asl.version>1.9.13</jackson-mapper-asl.version>
<aspectjweaver.version>1.8.7</aspectjweaver.version>
<slf4j-api.version>1.7.25</slf4j-api.version>
<freemarker.version>2.3.20</freemarker.version>
<junit.version>4.11</junit.version>
<jetty-server.version>9.2.22.v20170606</jetty-server.version>
<hessian.version>4.0.38</hessian.version>
<httpclient.version>4.3.6</httpclient.version>
<commons-exec.version>1.3</commons-exec.version>
<commons-beanutils.version>1.9.2</commons-beanutils.version>
<commons-lang.version>2.6</commons-lang.version>
<c3p0.version>0.9.5.2</c3p0.version>
<mysql-connector-java.version>5.1.29</mysql-connector-java.version>
<mybatis-spring.version>1.2.2</mybatis-spring.version>
<mybatis.version>3.2.8</mybatis.version>
<groovy-all.version>2.4.5</groovy-all.version>
<mail.version>1.4.6</mail.version>
<quartz.version>2.3.0</quartz.version>
<spring-boot.version>1.5.6.RELEASE</spring-boot.version>
</properties>
<build>
<plugins>
<plugin>
......
......@@ -4,15 +4,11 @@
<parent>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version>
<version>1.8.2-SNAPSHOT</version>
</parent>
<artifactId>xxl-job-admin</artifactId>
<packaging>war</packaging>
<properties>
<spring.version>3.2.17.RELEASE</spring.version>
</properties>
<dependencies>
<!-- springframe start -->
<dependency>
......@@ -40,59 +36,59 @@
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
<version>${aspectjweaver.version}</version>
</dependency>
<!-- jackson (support spring json) -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
<version>${jackson-mapper-asl.version}</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
<version>${slf4j-api.version}</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
<version>${freemarker.version}</version>
</dependency>
<!-- commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
<version>${commons-beanutils.version}</version>
</dependency>
<!-- commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<version>${commons-lang.version}</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<version>${javax.servlet-api.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<version>${jsp-api.version}</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
......@@ -100,45 +96,46 @@
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
<version>${c3p0.version}</version>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
<version>${mybatis-spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
<version>${mybatis.version}</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
<version>${httpclient.version}</version>
</dependency>
<!-- javax.mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.6</version>
<version>${mail.version}</version>
</dependency>
<!-- quartz :quartz-2.2.3/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
<version>${quartz.version}</version>
</dependency>
<!-- xxl-job-core -->
......
package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermessionLimit;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.rpc.codec.RpcRequest;
import com.xxl.job.core.rpc.codec.RpcResponse;
import com.xxl.job.core.rpc.netcom.NetComServerFactory;
......@@ -46,7 +47,7 @@ public class JobApiController {
}
}
@RequestMapping("/api")
@RequestMapping(AdminBiz.MAPPING)
@PermessionLimit(limit=false)
public void api(HttpServletRequest request, HttpServletResponse response) throws IOException {
......
......@@ -33,7 +33,7 @@ public class JobInfoController {
private XxlJobService xxlJobService;
@RequestMapping
public String index(Model model) {
public String index(Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
// 枚举-字典
model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表
......@@ -44,6 +44,8 @@ public class JobInfoController {
// 任务组
List<XxlJobGroup> jobGroupList = xxlJobGroupDao.findAll();
model.addAttribute("JobGroupList", jobGroupList);
model.addAttribute("jobGroup", jobGroup);
return "jobinfo/jobinfo.index";
}
......
......@@ -3,6 +3,7 @@ package com.xxl.job.admin.controller;
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.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao;
......@@ -12,6 +13,8 @@ import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -32,6 +35,7 @@ import java.util.Map;
@Controller
@RequestMapping("/joblog")
public class JobLogController {
private static Logger logger = LoggerFactory.getLogger(JobLogController.class);
@Resource
private XxlJobGroupDao xxlJobGroupDao;
......@@ -116,7 +120,7 @@ public class JobLogController {
@ResponseBody
public ReturnT<LogResult> logDetailCat(String executorAddress, long triggerTime, int logId, int fromLineNum){
try {
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, executorAddress).getObject();
ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(executorAddress);
ReturnT<LogResult> logResult = executorBiz.log(triggerTime, logId, fromLineNum);
// is end
......@@ -129,7 +133,7 @@ public class JobLogController {
return logResult;
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage());
}
}
......@@ -148,14 +152,14 @@ public class JobLogController {
}
// request of kill
ExecutorBiz executorBiz = null;
ReturnT<String> runResult = null;
try {
executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, log.getExecutorAddress()).getObject();
ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(log.getExecutorAddress());
runResult = executorBiz.kill(jobInfo.getId());
} catch (Exception e) {
e.printStackTrace();
return new ReturnT<String>(500, e.getMessage());
logger.error(e.getMessage(), e);
runResult = new ReturnT<String>(500, e.getMessage());
}
ReturnT<String> runResult = executorBiz.kill(jobInfo.getId());
if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
log.setHandleCode(ReturnT.FAIL_CODE);
......
package com.xxl.job.admin.core.route;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -24,30 +22,4 @@ public abstract class ExecutorRouter {
*/
public abstract ReturnT<String> routeRun(TriggerParam triggerParam, ArrayList<String> addressList);
/**
* run executor
* @param triggerParam
* @param address
* @return ReturnT.content: final address
*/
public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address){
ReturnT<String> runResult = null;
try {
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
runResult = executorBiz.run(triggerParam);
} catch (Exception e) {
logger.error("", e);
runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
}
StringBuffer runResultSB = new StringBuffer("触发调度:");
runResultSB.append("<br>address:").append(address);
runResultSB.append("<br>code:").append(runResult.getCode());
runResultSB.append("<br>msg:").append(runResult.getMsg());
runResult.setMsg(runResultSB.toString());
runResult.setContent(address);
return runResult;
}
}
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import java.util.ArrayList;
......@@ -25,7 +26,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
// beat
ReturnT<String> idleBeatResult = null;
try {
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
idleBeatResult = executorBiz.idleBeat(triggerParam.getJobId());
} catch (Exception e) {
logger.error(e.getMessage(), e);
......@@ -40,7 +41,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
// beat success
if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) {
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
idleBeatResultSB.append("<br><br>").append(runResult.getMsg());
// result
......
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
......@@ -82,7 +83,7 @@ public class ExecutorRouteConsistentHash extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList);
// run executor
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address);
return runResult;
}
......
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import java.util.ArrayList;
......@@ -25,7 +26,7 @@ public class ExecutorRouteFailover extends ExecutorRouter {
// beat
ReturnT<String> beatResult = null;
try {
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject();
ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
beatResult = executorBiz.beat();
} catch (Exception e) {
logger.error(e.getMessage(), e);
......@@ -40,7 +41,7 @@ public class ExecutorRouteFailover extends ExecutorRouter {
// beat success
if (beatResult.getCode() == ReturnT.SUCCESS_CODE) {
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
beatResultSB.append("<br><br>").append(runResult.getMsg());
// result
......
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
......@@ -23,7 +23,7 @@ public class ExecutorRouteFirst extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList);
// run executor
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address);
return runResult;
}
......
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
......@@ -62,7 +63,7 @@ public class ExecutorRouteLFU extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList);
// run executor
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address);
return runResult;
}
......
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
......@@ -61,7 +62,7 @@ public class ExecutorRouteLRU extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList);
// run executor
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address);
return runResult;
}
......
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
......@@ -22,7 +22,7 @@ public class ExecutorRouteLast extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList);
// run executor
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address);
return runResult;
}
......
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
......@@ -25,7 +26,7 @@ public class ExecutorRouteRandom extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList);
// run executor
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address);
return runResult;
}
......
package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
......@@ -41,7 +42,7 @@ public class ExecutorRouteRound extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList);
// run executor
ReturnT<String> runResult = runExecutor(triggerParam, address);
ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address);
return runResult;
}
......
......@@ -30,7 +30,7 @@ public class JobFailMonitorHelper {
private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>(0xfff8);
private Thread monitorThread;
private boolean toStop = false;
private volatile boolean toStop = false;
public void start(){
monitorThread = new Thread(new Runnable() {
......
......@@ -28,7 +28,7 @@ public class JobRegistryMonitorHelper {
}
private Thread registryThread;
private boolean toStop = false;
private volatile boolean toStop = false;
public void start(){
registryThread = new Thread(new Runnable() {
@Override
......
......@@ -5,9 +5,9 @@ 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.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.thread.JobFailMonitorHelper;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
......@@ -90,12 +90,12 @@ public class XxlJobTrigger {
triggerParam.setBroadcastTotal(addressList.size()); // update02
// 4.2、trigger-run (route run / trigger remote executor)
triggerResult = ExecutorRouter.runExecutor(triggerParam, address); // update03
triggerResult = runExecutor(triggerParam, address); // update03
triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
// 4.3、trigger (fail retry)
if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
triggerResult = ExecutorRouter.runExecutor(triggerParam, address); // update04
triggerResult = runExecutor(triggerParam, address); // update04
triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
}
}
......@@ -179,4 +179,30 @@ public class XxlJobTrigger {
logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
}
/**
* run executor
* @param triggerParam
* @param address
* @return ReturnT.content: final address
*/
public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address){
ReturnT<String> runResult = null;
try {
ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
runResult = executorBiz.run(triggerParam);
} catch (Exception e) {
logger.error(e.getMessage(), e);
runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
}
StringBuffer runResultSB = new StringBuffer("触发调度:");
runResultSB.append("<br>address:").append(address);
runResultSB.append("<br>code:").append(runResult.getCode());
runResultSB.append("<br>msg:").append(runResult.getMsg());
runResult.setMsg(runResultSB.toString());
runResult.setContent(address);
return runResult;
}
}
......@@ -65,6 +65,7 @@
<bean id="xxlJobDynamicScheduler" class="com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler" init-method="init" destroy-method="destroy" >
<!-- (轻易不要变更“调度器名称”, 任务创建时会绑定该“调度器名称”) -->
<property name="scheduler" ref="quartzScheduler"/>
<property name="accessToken" value="${xxl.job.accessToken}" />
</bean>
</beans>
\ No newline at end of file
......@@ -12,6 +12,9 @@ xxl.job.mail.password=asdfzxcv
xxl.job.mail.sendFrom=ovono802302@163.com
xxl.job.mail.sendNick=《任务调度平台XXL-JOB》
# xxl-job login
### xxl-job login
xxl.job.login.username=admin
xxl.job.login.password=123456
\ No newline at end of file
xxl.job.login.password=123456
### xxl-job, access token
xxl.job.accessToken=
\ No newline at end of file
......@@ -175,11 +175,12 @@
<#macro commonFooter >
<footer class="main-footer">
Powered by <b>XXL-JOB</b> 1.8.1(快照版)
Powered by <b>XXL-JOB</b> 1.8.2(快照版本)
<div class="pull-right hidden-xs">
<strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;
<a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>&nbsp;
<a href="http://my.oschina.net/xuxueli/blog/690978" target="_blank" >oschina</a>
<a href="http://www.xuxueli.com/" target="_blank" >xuxueli</a>
&nbsp;
<a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>
</strong><!-- All rights reserved. -->
</div>
</footer>
......
......@@ -31,33 +31,14 @@
<h4>简介:XXL-JOB</h4>
<br>
<p>
<a target="_blank" href="https://github.com/xuxueli/xxl-job">github地址</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a target="_blank" href="http://www.xuxueli.com/">xuxueli</a>
<br><br>
<a target="_blank" href="https://github.com/xuxueli/xxl-job">github</a>&nbsp;&nbsp;&nbsp;&nbsp;
<iframe src="https://ghbtns.com/github-btn.html?user=xuxueli&repo=xxl-job&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px" style="margin-bottom:-5px;"></iframe>
<br><br>
<a target="_blank" href="http://my.oschina.net/xuxueli/blog/690978">oschina地址</a>
<br><br>
<a >技术交流群5:138274130</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=a3f3aea7e5943e7a24e9726495747ddc19bccd3592d7a70ecb5a97b616062241">
<img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="《xxl-javaer》(五群)" title="《xxl-javaer》(五群)">
</a>
<br><br>
<a >技术交流群4:464762661</a>&nbsp;&nbsp;&nbsp;&nbsp;
(群即将满,请加群5)
<a target="_blank" href="http://my.oschina.net/xuxueli/blog/690978">oschina(文档中有交流群)</a>
<br><br>
<a >技术交流群3:242151780</a>&nbsp;&nbsp;&nbsp;&nbsp;
(群即将满,请加群5)
<br><br>
<a >技术交流群2:438249535</a>&nbsp;&nbsp;&nbsp;&nbsp;
(群即将满,请加群5)
<br><br>
<a >技术交流群1:367260654</a>&nbsp;&nbsp;&nbsp;&nbsp;
(群即将满,请加群5)
</p>
<p></p>
</div>
......
......@@ -37,7 +37,7 @@
<span class="input-group-addon">执行器</span>
<select class="form-control" id="jobGroup" >
<#list JobGroupList as group>
<option value="${group.id}" >${group.title}</option>
<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
</#list>
</select>
</div>
......@@ -110,7 +110,7 @@
<div class="col-sm-4">
<select class="form-control" name="jobGroup" >
<#list JobGroupList as group>
<option value="${group.id}" >${group.title}</option>
<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
</#list>
</select>
</div>
......
......@@ -167,6 +167,13 @@ $(function() {
jobTable.fnDraw();
});
// jobGroup change
$('#jobGroup').on('change', function(){
//reload
var jobGroup = $('#jobGroup').val();
window.location.href = base_url + "/jobinfo?jobGroup=" + jobGroup;
});
// job operate
$("#job_list").on('click', '.job_operate',function() {
var typeName;
......
package com.xxl.job.dao.impl;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.RegistryConfig;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import org.junit.Assert;
import org.junit.Test;
/**
* admin-api client, test
* @author xuxueli 2017-07-28 22:14:52
*/
public class AdminBizTest {
@Test
public void registryTest() throws Exception {
// admin-client
String addressUrl = "http://127.0.0.1:8080/xxl-job-admin".concat(AdminBiz.MAPPING);
String accessToken = null;
AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, addressUrl, accessToken).getObject();
// test executor registry
RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), "xxl-job-executor-example", "127.0.0.1:9999");
ReturnT<String> returnT = adminBiz.registry(registryParam);
Assert.assertTrue(returnT.getCode() == ReturnT.SUCCESS_CODE);
}
}
......@@ -4,7 +4,7 @@
<parent>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version>
<version>1.8.2-SNAPSHOT</version>
</parent>
<artifactId>xxl-job-core</artifactId>
<packaging>jar</packaging>
......@@ -13,56 +13,52 @@
<description>A lightweight distributed task scheduling framework.</description>
<url>http://www.xuxueli.com/</url>
<properties>
<spring.version>3.2.17.RELEASE</spring.version>
</properties>
<dependencies>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<version>${javax.servlet-api.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<version>${jsp-api.version}</version>
</dependency>
<!-- jetty -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.2.21.v20170120</version>
<version>${jetty-server.version}</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
<version>${slf4j-api.version}</version>
</dependency>
<!-- hessian -->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
<version>${hessian.version}</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
<version>${jackson-mapper-asl.version}</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
<version>${httpclient.version}</version>
</dependency>
<!-- spring-context -->
......@@ -76,14 +72,14 @@
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.5</version>
<version>${groovy-all.version}</version>
</dependency>
<!-- commons-exec -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.3</version>
<version>${commons-exec.version}</version>
</dependency>
</dependencies>
......
......@@ -11,6 +11,8 @@ import java.util.List;
*/
public interface AdminBiz {
public static final String MAPPING = "/api";
/**
* callback
*
......
package com.xxl.job.core.executor;
import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.impl.ExecutorBizImpl;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.JobHander;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import com.xxl.job.core.rpc.netcom.NetComServerFactory;
import com.xxl.job.core.thread.ExecutorRegistryThread;
import com.xxl.job.core.thread.JobThread;
import com.xxl.job.core.thread.TriggerCallbackThread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by xuxueli on 2016/3/2 21:14.
*/
public class XxlJobExecutor implements ApplicationContextAware, ApplicationListener {
public class XxlJobExecutor implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);
// ---------------------- param ----------------------
private String ip;
private int port = 9999;
private String appName;
public static String adminAddresses;
public static String logPath;
private String adminAddresses;
private String accessToken;
private String logPath;
public void setIp(String ip) {
this.ip = ip;
......@@ -44,48 +46,98 @@ public class XxlJobExecutor implements ApplicationContextAware, ApplicationListe
public void setAdminAddresses(String adminAddresses) {
this.adminAddresses = adminAddresses;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public void setLogPath(String logPath) {
this.logPath = logPath;
}
// ---------------------------------- job server ------------------------------------
private NetComServerFactory serverFactory = new NetComServerFactory();
public void start() throws Exception {
// executor start
NetComServerFactory.putService(ExecutorBiz.class, new ExecutorBizImpl()); // rpc-service, base on jetty
serverFactory.start(port, ip, appName);
// trigger callback thread start
TriggerCallbackThread.getInstance().start();
// ---------------------- applicationContext ----------------------
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void destroy(){
// 1、executor registry thread stop
ExecutorRegistryThread.getInstance().toStop();
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
// ---------------------- start + stop ----------------------
public void start() throws Exception {
// init admin-client
initAdminBizList(adminAddresses, accessToken);
// init executor-jobHandlerRepository
initJobHandlerRepository(applicationContext);
// 2、executor stop
serverFactory.destroy();
// init logpath
if (logPath!=null && logPath.trim().length()>0) {
XxlJobFileAppender.logPath = logPath;
}
// 3、job thread repository destory
// init executor-server
initExecutorServer(port, ip, appName, accessToken);
}
public void destroy(){
// destory JobThreadRepository
if (JobThreadRepository.size() > 0) {
for (Map.Entry<Integer, JobThread> item: JobThreadRepository.entrySet()) {
JobThread jobThread = item.getValue();
jobThread.toStop("Web容器销毁终止");
jobThread.interrupt();
removeJobThread(item.getKey(), "Web容器销毁终止");
}
JobThreadRepository.clear();
}
// 4、trigger callback thread stop
TriggerCallbackThread.getInstance().toStop();
// destory executor-server
stopExecutorServer();
}
// ---------------------- admin-client ----------------------
private static List<AdminBiz> adminBizList;
private static void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
if (adminAddresses!=null && adminAddresses.trim().length()>0) {
for (String address: adminAddresses.trim().split(",")) {
if (address!=null && address.trim().length()>0) {
String addressUrl = address.concat(AdminBiz.MAPPING);
AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, addressUrl, accessToken).getObject();
if (adminBizList == null) {
adminBizList = new ArrayList<AdminBiz>();
}
adminBizList.add(adminBiz);
}
}
}
}
public static List<AdminBiz> getAdminBizList(){
return adminBizList;
}
// ---------------------- executor-server(jetty) ----------------------
private NetComServerFactory serverFactory = new NetComServerFactory();
private void initExecutorServer(int port, String ip, String appName, String accessToken) throws Exception {
NetComServerFactory.putService(ExecutorBiz.class, new ExecutorBizImpl()); // rpc-service, base on jetty
NetComServerFactory.setAccessToken(accessToken);
serverFactory.start(port, ip, appName); // jetty + registry
}
private void stopExecutorServer() {
serverFactory.destroy(); // jetty + registry + callback
}
// ---------------------------------- init job handler ------------------------------------
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
XxlJobExecutor.applicationContext = applicationContext;
// ---------------------- job handler repository ----------------------
private static ConcurrentHashMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();
public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
logger.info("xxl-job register jobhandler success, name:{}, jobHandler:{}", name, jobHandler);
return jobHandlerRepository.put(name, jobHandler);
}
public static IJobHandler loadJobHandler(String name){
return jobHandlerRepository.get(name);
}
private static void initJobHandlerRepository(ApplicationContext applicationContext){
// init job handler action
Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHander.class);
......@@ -101,27 +153,10 @@ public class XxlJobExecutor implements ApplicationContextAware, ApplicationListe
}
}
}
}
// ---------------------------------- destory job executor ------------------------------------
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
if(applicationEvent instanceof ContextClosedEvent){
// TODO
}
}
// ---------------------------------- job handler repository
private static ConcurrentHashMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();
public static IJobHandler registJobHandler(String name, IJobHandler jobHandler){
logger.info("xxl-job register jobhandler success, name:{}, jobHandler:{}", name, jobHandler);
return jobHandlerRepository.put(name, jobHandler);
}
public static IJobHandler loadJobHandler(String name){
return jobHandlerRepository.get(name);
}
// ---------------------------------- job thread repository
// ---------------------- job thread repository ----------------------
private static ConcurrentHashMap<Integer, JobThread> JobThreadRepository = new ConcurrentHashMap<Integer, JobThread>();
public static JobThread registJobThread(int jobId, IJobHandler handler, String removeOldReason){
JobThread newJobThread = new JobThread(jobId, handler);
......
......@@ -52,21 +52,21 @@ public class GlueFactory {
try {
Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);
if (resource.name()!=null && resource.name().length()>0){
fieldBean = XxlJobExecutor.applicationContext.getBean(resource.name());
fieldBean = XxlJobExecutor.getApplicationContext().getBean(resource.name());
} else {
fieldBean = XxlJobExecutor.applicationContext.getBean(field.getName());
fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getName());
}
} catch (Exception e) {
}
if (fieldBean==null ) {
fieldBean = XxlJobExecutor.applicationContext.getBean(field.getType());
fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getType());
}
} else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) {
Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class);
if (qualifier!=null && qualifier.value()!=null && qualifier.value().length()>0) {
fieldBean = XxlJobExecutor.applicationContext.getBean(qualifier.value());
fieldBean = XxlJobExecutor.getApplicationContext().getBean(qualifier.value());
} else {
fieldBean = XxlJobExecutor.applicationContext.getBean(field.getType());
fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getType());
}
}
......
package com.xxl.job.core.handler.impl;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobFileAppender;
......@@ -37,17 +36,17 @@ public class ScriptJobHandler extends IJobHandler {
String scriptFileName = null;
if (GlueTypeEnum.GLUE_SHELL == glueType) {
cmd = "bash";
scriptFileName = XxlJobExecutor.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".sh");
scriptFileName = XxlJobFileAppender.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".sh");
} else if (GlueTypeEnum.GLUE_PYTHON == glueType) {
cmd = "python";
scriptFileName = XxlJobExecutor.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".py");
scriptFileName = XxlJobFileAppender.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".py");
}
// make script file
ScriptUtil.markScriptFile(scriptFileName, gluesource);
// log file
String logFileName = XxlJobExecutor.logPath.concat(XxlJobFileAppender.contextHolder.get());
String logFileName = XxlJobFileAppender.logPath.concat(XxlJobFileAppender.contextHolder.get());
// invoke
XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------");
......
package com.xxl.job.core.log;
import com.xxl.job.core.biz.model.LogResult;
import com.xxl.job.core.executor.XxlJobExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -20,7 +19,8 @@ public class XxlJobFileAppender {
//public static ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static final InheritableThreadLocal<String> contextHolder = new InheritableThreadLocal<String>();
public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public static String logPath = "/data/applogs/xxl-job/jobhandler/";
/**
* log filename: yyyy-MM-dd/9999.log
*
......@@ -31,7 +31,7 @@ public class XxlJobFileAppender {
public static String makeLogFileName(Date triggerDate, int logId) {
// filePath/
File filePathDir = new File(XxlJobExecutor.logPath);
File filePathDir = new File(logPath);
if (!filePathDir.exists()) {
filePathDir.mkdirs();
}
......@@ -66,7 +66,7 @@ public class XxlJobFileAppender {
if (logFileName==null || logFileName.trim().length()==0) {
return;
}
File logFile = new File(XxlJobExecutor.logPath, logFileName);
File logFile = new File(logPath, logFileName);
if (!logFile.exists()) {
try {
......@@ -111,7 +111,7 @@ public class XxlJobFileAppender {
if (logFileName==null || logFileName.trim().length()==0) {
return new LogResult(fromLineNum, 0, "readLog fail, logFile not found", true);
}
File logFile = new File(XxlJobExecutor.logPath, logFileName);
File logFile = new File(logPath, logFileName);
if (!logFile.exists()) {
return new LogResult(fromLineNum, 0, "readLog fail, logFile not exists", true);
......
......@@ -12,12 +12,14 @@ public class RpcRequest implements Serializable{
private String serverAddress;
private long createMillisTime;
private String accessToken;
private String className;
private String methodName;
private Class<?>[] parameterTypes;
private Object[] parameters;
public String getServerAddress() {
return serverAddress;
}
......@@ -29,41 +31,62 @@ public class RpcRequest implements Serializable{
public long getCreateMillisTime() {
return createMillisTime;
}
public void setCreateMillisTime(long createMillisTime) {
this.createMillisTime = createMillisTime;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Class<?>[] getParameterTypes() {
return parameterTypes;
}
public void setParameterTypes(Class<?>[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
public Object[] getParameters() {
return parameters;
}
public void setParameters(Object[] parameters) {
this.parameters = parameters;
}
@Override
public String toString() {
return "NettyRequest [serverAddress=" + serverAddress + ", createMillisTime="
+ createMillisTime + ", className=" + className
+ ", methodName=" + methodName + ", parameterTypes="
+ Arrays.toString(parameterTypes) + ", parameters="
+ Arrays.toString(parameters) + "]";
return "RpcRequest{" +
"serverAddress='" + serverAddress + '\'' +
", createMillisTime=" + createMillisTime +
", accessToken='" + accessToken + '\'' +
", className='" + className + '\'' +
", methodName='" + methodName + '\'' +
", parameterTypes=" + Arrays.toString(parameterTypes) +
", parameters=" + Arrays.toString(parameters) +
'}';
}
}
......@@ -20,11 +20,13 @@ public class NetComClientProxy implements FactoryBean<Object> {
// ---------------------- config ----------------------
private Class<?> iface;
String serverAddress;
JettyClient client = new JettyClient();
public NetComClientProxy(Class<?> iface, String serverAddress) {
private String serverAddress;
private String accessToken;
private JettyClient client = new JettyClient();
public NetComClientProxy(Class<?> iface, String serverAddress, String accessToken) {
this.iface = iface;
this.serverAddress = serverAddress;
this.accessToken = accessToken;
}
@Override
......@@ -39,6 +41,7 @@ public class NetComClientProxy implements FactoryBean<Object> {
RpcRequest request = new RpcRequest();
request.setServerAddress(serverAddress);
request.setCreateMillisTime(System.currentTimeMillis());
request.setAccessToken(accessToken);
request.setClassName(method.getDeclaringClass().getName());
request.setMethodName(method.getName());
request.setParameterTypes(method.getParameterTypes());
......
......@@ -30,14 +30,18 @@ public class NetComServerFactory {
server.destroy();
}
// ---------------------- server init ----------------------
// ---------------------- server instance ----------------------
/**
* init local rpc service map
*/
private static Map<String, Object> serviceMap = new HashMap<String, Object>();
private static String accessToken;
public static void putService(Class<?> iface, Object serviceBean){
serviceMap.put(iface.getName(), serviceBean);
}
public static void setAccessToken(String accessToken) {
NetComServerFactory.accessToken = accessToken;
}
public static RpcResponse invokeService(RpcRequest request, Object serviceBean) {
if (serviceBean==null) {
serviceBean = serviceMap.get(request.getClassName());
......@@ -49,7 +53,11 @@ public class NetComServerFactory {
RpcResponse response = new RpcResponse();
if (System.currentTimeMillis() - request.getCreateMillisTime() > 180000) {
response.setResult(new ReturnT<String>(ReturnT.FAIL_CODE, "the timestamp difference between admin and executor exceeds the limit."));
response.setResult(new ReturnT<String>(ReturnT.FAIL_CODE, "The timestamp difference between admin and executor exceeds the limit."));
return response;
}
if (accessToken!=null && accessToken.trim().length()>0 && !accessToken.trim().equals(request.getAccessToken())) {
response.setResult(new ReturnT<String>(ReturnT.FAIL_CODE, "The access token[" + request.getAccessToken() + "] is wrong."));
return response;
}
......
......@@ -21,8 +21,8 @@ public class JettyClient {
// reqURL
String reqURL = request.getServerAddress();
if (reqURL!=null && reqURL.toLowerCase().indexOf("http://")==-1) {
reqURL = "http://" + request.getServerAddress() + "/";
if (reqURL!=null && reqURL.toLowerCase().indexOf("http")==-1) {
reqURL = "http://" + request.getServerAddress() + "/"; // IP:PORT, need parse to url
}
// remote invoke
......
package com.xxl.job.core.rpc.netcom.jetty.server;
import com.xxl.job.core.thread.ExecutorRegistryThread;
import com.xxl.job.core.thread.TriggerCallbackThread;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
......@@ -38,10 +39,16 @@ public class JettyServer {
server.setHandler(handlerc);
try {
// Start the server
// Start server
server.start();
logger.info(">>>>>>>>>>>> xxl-job jetty server start success at port:{}.", port);
// Start Registry-Server
ExecutorRegistryThread.getInstance().start(port, ip, appName);
// Start Callback-Server
TriggerCallbackThread.getInstance().start();
server.join(); // block until thread stopped
logger.info(">>>>>>>>>>> xxl-rpc server join success, netcon={}, port={}", JettyServer.class.getName(), port);
} catch (Exception e) {
......@@ -56,6 +63,8 @@ public class JettyServer {
}
public void destroy() {
// destroy server
if (server != null) {
try {
server.stop();
......@@ -67,6 +76,13 @@ public class JettyServer {
if (thread.isAlive()) {
thread.interrupt();
}
// destroy Registry-Server
ExecutorRegistryThread.getInstance().toStop();
// destroy Callback-Server
TriggerCallbackThread.getInstance().toStop();
logger.info(">>>>>>>>>>> xxl-rpc server destroy success, netcon={}", JettyServer.class.getName());
}
......
......@@ -5,7 +5,6 @@ import com.xxl.job.core.biz.model.RegistryParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.enums.RegistryConfig;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import com.xxl.job.core.util.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -32,7 +31,7 @@ public class ExecutorRegistryThread extends Thread {
logger.warn(">>>>>>>>>>>> xxl-job, executor registry config fail, appName is null.");
return;
}
if (XxlJobExecutor.adminAddresses==null || XxlJobExecutor.adminAddresses.trim().length()==0) {
if (XxlJobExecutor.getAdminBizList() == null) {
logger.warn(">>>>>>>>>>>> xxl-job, executor registry config fail, adminAddresses is null.");
return;
}
......@@ -49,15 +48,10 @@ public class ExecutorRegistryThread extends Thread {
@Override
public void run() {
while (!toStop) {
try {
RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, executorAddress);
for (String addressUrl: XxlJobExecutor.adminAddresses.split(",")) {
String apiUrl = addressUrl.concat("/api");
for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
try {
AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, apiUrl).getObject();
ReturnT<String> registryResult = adminBiz.registry(registryParam);
if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
registryResult = ReturnT.SUCCESS;
......@@ -71,7 +65,6 @@ public class ExecutorRegistryThread extends Thread {
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
......
......@@ -4,7 +4,6 @@ import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.model.HandleCallbackParam;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -43,17 +42,14 @@ public class TriggerCallbackThread {
callbackParamList.add(callback);
// valid
if (XxlJobExecutor.adminAddresses==null || XxlJobExecutor.adminAddresses.trim().length()==0) {
if (XxlJobExecutor.getAdminBizList()==null) {
logger.warn(">>>>>>>>>>>> xxl-job callback fail, adminAddresses is null, callbackParamList:{}", callbackParamList);
continue;
}
// callback, will retry if error
for (String addressUrl: XxlJobExecutor.adminAddresses.split(",")) {
String apiUrl = addressUrl.concat("/api");
for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
try {
AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, apiUrl).getObject();
ReturnT<String> callbackResult = adminBiz.callback(callbackParamList);
if (callbackResult!=null && ReturnT.SUCCESS_CODE == callbackResult.getCode()) {
callbackResult = ReturnT.SUCCESS;
......
package com.xxl.job.core.util;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.log.XxlJobFileAppender;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;
......@@ -28,7 +28,7 @@ public class ScriptUtil {
*/
public static void markScriptFile(String scriptFileName, String content) throws IOException {
// filePath/
File filePathDir = new File(XxlJobExecutor.logPath);
File filePathDir = new File(XxlJobFileAppender.logPath);
if (!filePathDir.exists()) {
filePathDir.mkdirs();
}
......
......@@ -4,7 +4,7 @@
<parent>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version>
<version>1.8.2-SNAPSHOT</version>
</parent>
<artifactId>xxl-job-executor-example</artifactId>
<packaging>war</packaging>
......@@ -13,12 +13,8 @@
<description>Executor project for spring boot.</description>
<url>http://www.xuxueli.com/</url>
<properties>
<spring.version>3.2.17.RELEASE</spring.version>
</properties>
<dependencies>
<!-- springframe start -->
<!-- spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
......@@ -29,20 +25,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
<version>${slf4j-api.version}</version>
</dependency>
<!-- xxl-job-core -->
......@@ -51,7 +34,6 @@
<artifactId>xxl-job-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -33,6 +33,8 @@
<property name="adminAddresses" value="${xxl.job.admin.addresses}" />
<!-- 执行器日志路径[必填] -->
<property name="logPath" value="${xxl.job.executor.logpath}" />
<!-- 访问令牌,非空则进行匹配校验[选填] -->
<property name="accessToken" value="${xxl.job.accessToken}" />
</bean>
......
......@@ -7,4 +7,7 @@ xxl.job.executor.ip=
xxl.job.executor.port=9999
### xxl-job log path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
\ No newline at end of file
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
### xxl-job, access token
xxl.job.accessToken=
\ No newline at end of file
......@@ -8,6 +8,8 @@ import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
/**
* executor-api client, test
*
* Created by xuxueli on 17/5/12.
*/
public class DemoJobHandlerTest {
......@@ -31,7 +33,8 @@ public class DemoJobHandlerTest {
triggerParam.setLogDateTim(System.currentTimeMillis());
// do remote trigger
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, "127.0.0.1:9999").getObject();
String accessToken = null;
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, "127.0.0.1:9999", null).getObject();
ReturnT<String> runResult = executorBiz.run(triggerParam);
}
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version>
<version>1.8.2-SNAPSHOT</version>
</parent>
<artifactId>xxl-job-executor-springboot-example</artifactId>
<packaging>jar</packaging>
......@@ -16,8 +16,6 @@
<url>http://www.xuxueli.com/</url>
<properties>
<spring-boot.version>1.3.8.RELEASE</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.7</java.version>
......@@ -33,41 +31,44 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- jetty -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty-server.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty-server.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${jetty-server.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${jetty-server.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- spring-boot-starter-web (提供了对web的支持,包含了spring webmvc和tomcat等web开发的特性) -->
<!-- spring-boot-starter-web (spring-webmvc + tomcat) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
......
......@@ -34,6 +34,8 @@ public class XxlJobConfig {
@Value("${xxl.job.executor.logpath}")
private String logpath;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Bean(initMethod = "start", destroyMethod = "destroy")
public XxlJobExecutor xxlJobExecutor() {
......@@ -44,6 +46,7 @@ public class XxlJobConfig {
xxlJobExecutor.setAppName(appname);
xxlJobExecutor.setAdminAddresses(addresses);
xxlJobExecutor.setLogPath(logpath);
xxlJobExecutor.setAccessToken(accessToken);
return xxlJobExecutor;
}
......
......@@ -15,3 +15,6 @@ xxl.job.executor.port=9998
### xxl-job log path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
### xxl-job, access token
xxl.job.accessToken=
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论