提交 3fda5448 编写于 作者: M 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
<p align="center">
# 分布式任务调度平台XXL-JOB <a href="http://www.xuxueli.com/">
<img src="https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg" width="150">
[![Build Status](https://travis-ci.org/xuxueli/xxl-job.svg?branch=master)](https://travis-ci.org/xuxueli/xxl-job) </a>
[![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/) <h3 align="center">XXL-JOB</h3>
[![GitHub release](https://img.shields.io/github/release/xuxueli/xxl-job.svg)](https://github.com/xuxueli/xxl-job/releases) <p align="center">
[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0.html) XXL-JOB, a lightweight distributed task scheduling framework.
[![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) <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是一个轻量级分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 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操作,操作简单,一分钟上手; - 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手;
- 2、动态:支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,即时生效; - 2、动态:支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,即时生效;
- 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现,可保证调度中心HA; - 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现,可保证调度中心HA;
...@@ -41,11 +68,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -41,11 +68,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
- 23、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发对应集群中所有执行器执行一次任务,同时传递分片参数;可根据分片参数开发分片任务; - 23、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发对应集群中所有执行器执行一次任务,同时传递分片参数;可根据分片参数开发分片任务;
- 24、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 - 24、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
### 架构图
![输入图片说明](https://static.oschina.net/uploads/img/201707/17190028_aEE2.png "在这里输入图片标题") ## Development
### 发展
于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计…… 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
于2015-11月,XXL-JOB终于RELEASE了第一个大版本V1.0, 随后我将之发布到OSCHINA,XXL-JOB在OSCHINA上获得了@红薯的热门推荐,同期分别达到了OSCHINA的“热门动弹”排行第一和git.oschina的开源软件月热度排行第一,在此特别感谢红薯,感谢大家的关注和支持。 于2015-11月,XXL-JOB终于RELEASE了第一个大版本V1.0, 随后我将之发布到OSCHINA,XXL-JOB在OSCHINA上获得了@红薯的热门推荐,同期分别达到了OSCHINA的“热门动弹”排行第一和git.oschina的开源软件月热度排行第一,在此特别感谢红薯,感谢大家的关注和支持。
...@@ -56,7 +80,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -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) )。 于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交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。 据最新统计, 自2016-01-21接入至2017-07-07期间,该系统已调度约60万余次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。
至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止2016-07-19为止,XXL-JOB已接入的公司包括不限于: 至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止2016-07-19为止,XXL-JOB已接入的公司包括不限于:
...@@ -94,60 +118,43 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -94,60 +118,43 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
- 31、四川互宜达科技有限公司 - 31、四川互宜达科技有限公司
- 32、钱包行云(北京)科技有限公司 - 32、钱包行云(北京)科技有限公司
- 33、重庆欣才集团 - 33、重庆欣才集团
- 34、咪咕互动娱乐有限公司(中国移动)
- 35、北京诺亦腾科技有限公司
- 36、增长引擎(北京)信息技术有限公司
- …… - ……
欢迎大家的关注和使用,XXL-JOB也将拥抱变化,持续发展。 欢迎大家的关注和使用,XXL-JOB也将拥抱变化,持续发展。
### 下载 ## Communication
#### 源码仓库地址 (将会在两个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)
#### 技术交流群 (仅作技术交流) - 腾讯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 ) ## Issue
- 群4:464762661 (群即将满,请加群5) 如有问题可在 [Github Issues](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群;
- 群3:242151780 (群即将满,请加群5)
- 群2:438249535 (群即将满,请加群5)
- 群1:367260654 (群即将满,请加群5)
### 报告问题 ## User Registration
XXL-JOB托管在Github上,如有问题可在 [ISSUES](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群; 登记仅为了产品推广,产品开源免费。
请接入使用的公司或个人进行用户登记 [登记地址](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)"。 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 "在这里输入图片标题") 微信:![输入图片说明](https://static.oschina.net/uploads/img/201707/07214300_qhxT.png "在这里输入图片标题")
支付宝:![输入图片说明](http://images2015.cnblogs.com/blog/554415/201605/554415-20160513183306234-1939652116.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
...@@ -86,13 +86,16 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -86,13 +86,16 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
- 31、四川互宜达科技有限公司 - 31、四川互宜达科技有限公司
- 32、钱包行云(北京)科技有限公司 - 32、钱包行云(北京)科技有限公司
- 33、重庆欣才集团 - 33、重庆欣才集团
- 34、咪咕互动娱乐有限公司(中国移动)
- 35、北京诺亦腾科技有限公司
- 36、增长引擎(北京)信息技术有限公司
- …… - ……
欢迎大家的关注和使用,XXL-JOB也将拥抱变化,持续发展。 欢迎大家的关注和使用,XXL-JOB也将拥抱变化,持续发展。
### 1.4 下载 ### 1.4 下载
#### 源码仓库地址 (将会在两个git仓库同步发布最新代码) #### 源码仓库地址
源码仓库地址 | Release Download 源码仓库地址 | Release Download
--- | --- --- | ---
...@@ -100,35 +103,36 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -100,35 +103,36 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
[http://git.oschina.net/xuxueli0323/xxl-job](http://git.oschina.net/xuxueli0323/xxl-job) | [Download](http://git.oschina.net/xuxueli0323/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/ --> <!-- http://repo1.maven.org/maven2/com/xuxueli/xxl-job-core/ -->
<dependency> <dependency>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId> <artifactId>xxl-job-core</artifactId>
<version>1.8.0</version> <version>1.8.1</version>
</dependency> </dependency>
``` ```
#### 博客地址 (将会在两个博客同步更新文档) #### 博客地址
- [oschina地址](http://my.oschina.net/xuxueli/blog/690978) - [oschina地址](http://my.oschina.net/xuxueli/blog/690978)
- [cnblogs地址](http://www.cnblogs.com/xuxueli/p/5021979.html) - [cnblogs地址](http://www.cnblogs.com/xuxueli/p/5021979.html)
#### 技术交流群 (仅作技术交流) #### 技术交流
- 群5:138274130 [![image](http://pub.idqqimg.com/wpa/images/group.png)](http://shang.qq.com/wpa/qunwpa?idkey=a3f3aea7e5943e7a24e9726495747ddc19bccd3592d7a70ecb5a97b616062241 ) - 腾讯QQ群(6):399758605
- 群4:464762661 (群即将满,请加群5) - 腾讯QQ群(5):138274130 (群即将满,请加群6)
- 群3:242151780 (群即将满,请加群5) - 腾讯QQ群(4):464762661 (群即将满,请加群6)
- 群2:438249535 (群即将满,请加群5) - 腾讯QQ群(3):242151780 (群即将满,请加群6)
- 群1:367260654 (群即将满,请加群5) - 腾讯QQ群(2):438249535 (群即将满,请加群6)
- 腾讯QQ群(1):367260654 (群即将满,请加群6)
### 1.5 环境 ### 1.5 环境
- JDK:1.7+ - JDK:1.7+
- Servlet/JSP Spec:3.1/2.3 - Servlet/JSP Spec:3.1/2.3
- Tomcat:8.5.x/Jetty9.2 - Tomcat:8.5.x/Jetty9.2.x
- Spring-boot:1.3.8/Spring4.x - Spring-boot:1.5.x/Spring4.x
- Mysql:5.6+ - Mysql:5.6+
- Maven:3+ - Maven:3+
...@@ -136,18 +140,18 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -136,18 +140,18 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
## 二、快速入门 ## 二、快速入门
### 2.1 初始化“调度数据库” ### 2.1 初始化“调度数据库”
请下载项目源码并解压,获取 "调度数据库初始化SQL脚本" 并执行即可。正常情况下应该生成16张表,脚本文件位置为: 请下载项目源码并解压,获取 "调度数据库初始化SQL脚本" 并执行即可,正常情况下应该生成16张表。
源码解压根目录\xxl-job\db\tables_xxl_job.sql "调度数据库初始化SQL脚本" 位置为:
/xxl-job/db/tables_xxl_job.sql
调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例; 调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例;
如果mysql做主从,调度中心集群节点务必强制走主库; 如果mysql做主从,调度中心集群节点务必强制走主库;
### 2.2 编译源码 ### 2.2 编译源码
解压源码,按照maven格式将源码导入IDE, 使用maven进行编译即可,源码结构如下图所示: 解压源码,按照maven格式将源码导入IDE, 使用maven进行编译即可,源码结构如下:
![输入图片说明](https://static.oschina.net/uploads/img/201705/11214348_aGgr.png "在这里输入图片标题")
xxl-job-admin:调度中心 xxl-job-admin:调度中心
xxl-job-core:公共依赖 xxl-job-core:公共依赖
...@@ -160,14 +164,16 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -160,14 +164,16 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
作用:统一管理任务调度平台上调度任务,负责触发调度执行。 作用:统一管理任务调度平台上调度任务,负责触发调度执行。
#### 步骤一:调度中心配置: #### 步骤一:调度中心配置:
配置文件以及配置属性如下图所示。 调度中心配置文件地址:
![输入图片说明](https://static.oschina.net/uploads/img/201705/11214752_Ifvp.png "在这里输入图片标题") /xxl-job/xxl-job-admin/src/main/resources/xxl-job-admin.properties
调度中心配置内容说明:
### 调度中心JDBC链接:链接地址请保持和 2.1章节 所创建的调度数据库的地址一致 ### 调度中心JDBC链接:链接地址请保持和 2.1章节 所创建的调度数据库的地址一致
xxl.job.db.driverClass=com.mysql.jdbc.Driver xxl.job.db.driverClass=com.mysql.jdbc.Driver
xxl.job.db.url=jdbc:mysql://localhost:3306/xxl-job?useUnicode=true&amp;characterEncoding=UTF-8 xxl.job.db.url=jdbc:mysql://localhost:3306/xxl-job?useUnicode=true&characterEncoding=UTF-8
xxl.job.db.user=root xxl.job.db.user=root
xxl.job.db.password=root_pwd xxl.job.db.password=root_pwd
...@@ -179,9 +185,12 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -179,9 +185,12 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
xxl.job.mail.sendFrom=ovono802302@163.com xxl.job.mail.sendFrom=ovono802302@163.com
xxl.job.mail.sendNick=《任务调度平台XXL-JOB》 xxl.job.mail.sendNick=《任务调度平台XXL-JOB》
# 登录账号 ### 登录账号
xxl.job.login.username=admin xxl.job.login.username=admin
xxl.job.login.password=123456 xxl.job.login.password=123456
### 调度中心通讯TOKEN,非空时启用
xxl.job.accessToken=
#### 步骤二:部署项目: #### 步骤二:部署项目:
如果已经正确进行上述配置,可将项目编译打war包并部署到tomcat中。 如果已经正确进行上述配置,可将项目编译打war包并部署到tomcat中。
...@@ -191,6 +200,13 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -191,6 +200,13 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
至此“调度中心”项目已经部署成功。 至此“调度中心”项目已经部署成功。
#### 步骤三:调度中心集群(可选):
调度中心支持集群部署,提升调度系统可用性。
集群部署唯一要求为:保证每个集群节点配置(db和登陆账号等)保持一致。调度中心通过db配置区分不同集群。
调度中心在集群部署时可通过nginx负载均衡,此时可以为集群分配一个域名。该域名一方面可以用于访问,另一方面也可以用于配置执行器回调地址。
### 2.4 配置部署“执行器项目” ### 2.4 配置部署“执行器项目”
“执行器”项目:xxl-job-executor-example (如新建执行器项目,可参考该Example执行器项目的配置步骤;) “执行器”项目:xxl-job-executor-example (如新建执行器项目,可参考该Example执行器项目的配置步骤;)
...@@ -200,10 +216,11 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -200,10 +216,11 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
确认pom文件中引入了 "xxl-job-core" 的maven依赖; 确认pom文件中引入了 "xxl-job-core" 的maven依赖;
#### 步骤二:执行器配置 #### 步骤二:执行器配置
配置文件以及配置属性如下图所示。 执行器配置配置文件地址:
![输入图片说明](https://static.oschina.net/uploads/img/201705/11214800_7G3o.png "在这里输入图片标题") /xxl-job/xxl-job-executor-example/src/main/resources/xxl-job-executor.properties
执行器配置配置内容说明:
### xxl-job admin address list:调度中心部署跟地址:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调"。 ### xxl-job admin address list:调度中心部署跟地址:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调"。
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
...@@ -215,6 +232,9 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -215,6 +232,9 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
### xxl-job log path:执行器运行日志文件存储的磁盘位置 ### xxl-job log path:执行器运行日志文件存储的磁盘位置
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/ xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
### xxl-job, access token:执行器通讯TOKEN,非空时启用
xxl.job.accessToken=
#### 步骤三:执行器组件配置 #### 步骤三:执行器组件配置
...@@ -225,7 +245,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -225,7 +245,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
1、JobHandler 扫描路径:自动扫描容器中JobHandler; 1、JobHandler 扫描路径:自动扫描容器中JobHandler;
2、执行器Excutor配置:执行器核心配置; 2、执行器Excutor配置:执行器核心配置;
#### 步骤四:部署项目: #### 步骤四:部署执行器项目:
如果已经正确进行上述配置,可将执行器项目编译打部署,系统提供两个执行器example项目,选择其中一个即可,各自的部署方式如下。 如果已经正确进行上述配置,可将执行器项目编译打部署,系统提供两个执行器example项目,选择其中一个即可,各自的部署方式如下。
xxl-job-executor-example:项目编译打包成WAR包,并部署到tomcat中。 xxl-job-executor-example:项目编译打包成WAR包,并部署到tomcat中。
...@@ -233,6 +253,11 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -233,6 +253,11 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
至此“执行器”项目已经部署结束。 至此“执行器”项目已经部署结束。
#### 步骤五:执行器集群(可选):
执行器支持集群部署,提升调度系统可用性,同时提升任务处理能力。
集群部署唯一要求为:保证集群中每个执行器的配置项 "xxl.job.admin.addresses/调度中心地址" 保持一致,执行器根据该配置进行执行器自动注册等操作。
### 2.5 开发第一个任务“Hello World” ### 2.5 开发第一个任务“Hello World”
本示例以新建一个 “GLUE模式(Java)” 运行模式的任务为例。更多有关任务的详细配置,请查看“章节三:任务详解”。 本示例以新建一个 “GLUE模式(Java)” 运行模式的任务为例。更多有关任务的详细配置,请查看“章节三:任务详解”。
...@@ -706,6 +731,16 @@ XXL-JOB会为每次调度请求生成一个单独的日志文件,需要通过 ...@@ -706,6 +731,16 @@ XXL-JOB会为每次调度请求生成一个单独的日志文件,需要通过
- 1、分片任务场景:10个执行器的集群来处理10w条数据,每台机器只需要处理1w条数据,耗时降低10倍; - 1、分片任务场景:10个执行器的集群来处理10w条数据,每台机器只需要处理1w条数据,耗时降低10倍;
- 2、广播任务场景:广播执行器机器运行shell脚本、广播集群节点进行缓存更新等 - 2、广播任务场景:广播执行器机器运行shell脚本、广播集群节点进行缓存更新等
#### 5、10 访问令牌(AccessToken)
为提升系统安全性,调度中心和执行器进行安全性校验,双方AccessToken匹配才允许通讯;
调度中心和执行器,可通过配置项 "xxl.job.accessToken" 进行AccessToken的设置。
调度中心和执行器,如果需要正常通讯,只有两种设置;
- 设置一:调度中心和执行器,均不设置AccessToken;关闭安全性校验;
- 设置二:调度中心和执行器,设置了相同的AccessToken;
## 六、版本更新日志 ## 六、版本更新日志
#### 6.1 版本 V1.1.x,新特性[2015-12-05] #### 6.1 版本 V1.1.x,新特性[2015-12-05]
...@@ -896,41 +931,49 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段 ...@@ -896,41 +931,49 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 10、执行日志,支持根据运行 "状态" 筛选日志; - 10、执行日志,支持根据运行 "状态" 筛选日志;
- 11、调度中心任务注册检测逻辑优化; - 11、调度中心任务注册检测逻辑优化;
#### 6.18 版本 V1.8.1 特性[快照版本] #### 6.18 版本 V1.8.1 特性[2017-07-30]
- 1、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数处理分片任务; - 1、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数处理分片任务;
- 2、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 - 2、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
- 3、执行器JobHandler禁止命名冲突; - 3、执行器JobHandler禁止命名冲突;
- 4、执行器集群地址列表进行自然排序; - 4、执行器集群地址列表进行自然排序;
- 5、调度中心,DAO层代码精简优化并且新增测试用例覆盖; - 5、调度中心,DAO层代码精简优化并且新增测试用例覆盖;
- 6、调度中心API服务改为自研RPC形式,统一底层通讯模型; - 6、调度中心API服务改为自研RPC形式,统一底层通讯模型;
- 7、新增调度中心API服务测试Demo,方便在调度中心API扩展和测试;
- 8、任务列表页交互优化,更换执行器分组时自动刷新任务列表,新建任务时默认定位在当前执行器位置;
- 9、访问令牌(accessToken):为提升系统安全性,调度中心和执行器进行安全性校验,双方AccessToken匹配才允许通讯;
- 10、springboot版本执行器,升级至1.5.6.RELEASE版本;
- 11、统一maven依赖版本管理;
#### TODO LIST #### TODO LIST
- 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限;
- 2、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动; - 2、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动;目前采用IP自然排序,可以满足需求,待定;
- 3、失败重试优化:目前失败重试逻辑为,在本次调度请求失败后重新执行一次请求逻辑。优化点为针对调度和执行失败时均做失败重试,重试时重新触发一次完整调度,这将可能导致失败是调度死循环,考虑中 - 3、失败重试优化:目前失败重试逻辑为,在本次调度请求失败后重新执行一次请求逻辑。优化点为针对调度和执行失败时均做失败重试,重试时重新触发一次完整调度,这将可能导致失败是调度死循环,待定
- 4、回调失败写文件,查看日志时读文件确认,重启后回调确认; - 4、回调失败写文件,查看日志时读文件确认,重启后回调确认;
- 5、任务依赖,流程图,子任务+会签任务,各节点日志; - 5、任务依赖,流程图,子任务+会签任务,各节点日志;
- 6、调度任务优先级; - 6、调度任务优先级;
- 7、移除quartz依赖,重写调度模块:新增或恢复任务时将下次执行记录插入delayqueue,调度中心集群竞争分布式锁,成功节点批量加载到期delayqueue数据,批量执行。 - 7、移除quartz依赖,重写调度模块:新增或恢复任务时将下次执行记录插入delayqueue,调度中心集群竞争分布式锁,成功节点批量加载到期delayqueue数据,批量执行。
- 8、任务执行结果回调失败后重试:待定,防止回调死循环 - 8、springboot 和 docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用
- 9、springboot 和 docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用; - 9、国际化:调度中心界面 + 官方文档,新增英文版本。
- 10、安全校验:调度中心和执行器约定公共密匙,只有密匙一致才允许相互通讯; - 10、执行器摘除:执行器销毁时,主动通知调度中心并摘除对应执行器节点,提高执行器状态感知的时效性。
## 七、其他 ## 七、其他
#### 7.1 报告问题 #### 7.1 报告问题
XXL-JOB托管在Github上,如有问题可在 [ISSUES](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群; XXL-JOB托管在Github上,如有问题可在 [ISSUES](https://github.com/xuxueli/xxl-job/issues/) 上提问,也可以加入上文技术交流群;
#### 7.2 接入登记(登记仅为了推广,产品开源免费) #### 7.2 用户接入登记
更多接入公司,欢迎在github [登记](https://github.com/xuxueli/xxl-job/issues/1 ) 登记仅为了产品推广,产品开源免费。
请接入使用的公司或个人进行用户登记 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 )
#### 7.3 开源协议 #### 7.3 开源协议和版权
产品开源免费,并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。 产品开源免费,并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。
XXL-JOB采用GPLv3协议,目的是为了保证用户的自由使用权利。协议可避免专利申请的特殊危险 "the GPL assures that patents cannot be used to render the program non-free.(摘自GPLv3)"。 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) 的建设:) #### 捐赠
支持的话可以扫一扫,请作者喝杯咖啡吧:)
微信:![输入图片说明](https://static.oschina.net/uploads/img/201707/07214300_qhxT.png "在这里输入图片标题") 微信:![输入图片说明](https://static.oschina.net/uploads/img/201707/07214300_qhxT.png "在这里输入图片标题")
支付宝:![输入图片说明](http://images2015.cnblogs.com/blog/554415/201605/554415-20160513183306234-1939652116.png "在这里输入图片标题") 支付宝:![输入图片说明](http://images2015.cnblogs.com/blog/554415/201605/554415-20160513183306234-1939652116.png "在这里输入图片标题")
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<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>1.8.1-SNAPSHOT</version> <version>1.8.2-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
...@@ -17,6 +17,37 @@ ...@@ -17,6 +17,37 @@
<module>xxl-job-executor-springboot-example</module> <module>xxl-job-executor-springboot-example</module>
</modules> </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> <build>
<plugins> <plugins>
<plugin> <plugin>
......
...@@ -4,15 +4,11 @@ ...@@ -4,15 +4,11 @@
<parent> <parent>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version> <version>1.8.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-admin</artifactId> <artifactId>xxl-job-admin</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<properties>
<spring.version>3.2.17.RELEASE</spring.version>
</properties>
<dependencies> <dependencies>
<!-- springframe start --> <!-- springframe start -->
<dependency> <dependency>
...@@ -40,59 +36,59 @@ ...@@ -40,59 +36,59 @@
<dependency> <dependency>
<groupId>org.aspectj</groupId> <groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId> <artifactId>aspectjweaver</artifactId>
<version>1.8.7</version> <version>${aspectjweaver.version}</version>
</dependency> </dependency>
<!-- jackson (support spring json) --> <!-- jackson (support spring json) -->
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId> <artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version> <version>${jackson-mapper-asl.version}</version>
</dependency> </dependency>
<!-- slf4j --> <!-- slf4j -->
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId> <artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version> <version>${slf4j-api.version}</version>
</dependency> </dependency>
<!-- freemarker --> <!-- freemarker -->
<dependency> <dependency>
<groupId>org.freemarker</groupId> <groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId> <artifactId>freemarker</artifactId>
<version>2.3.20</version> <version>${freemarker.version}</version>
</dependency> </dependency>
<!-- commons-beanutils --> <!-- commons-beanutils -->
<dependency> <dependency>
<groupId>commons-beanutils</groupId> <groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId> <artifactId>commons-beanutils</artifactId>
<version>1.9.2</version> <version>${commons-beanutils.version}</version>
</dependency> </dependency>
<!-- commons-lang --> <!-- commons-lang -->
<dependency> <dependency>
<groupId>commons-lang</groupId> <groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId> <artifactId>commons-lang</artifactId>
<version>2.6</version> <version>${commons-lang.version}</version>
</dependency> </dependency>
<!-- servlet --> <!-- servlet -->
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version> <version>${javax.servlet-api.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.servlet.jsp</groupId> <groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId> <artifactId>jsp-api</artifactId>
<version>2.2</version> <version>${jsp-api.version}</version>
</dependency> </dependency>
<!-- junit --> <!-- junit -->
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.11</version> <version>${junit.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
...@@ -100,45 +96,46 @@ ...@@ -100,45 +96,46 @@
<dependency> <dependency>
<groupId>com.mchange</groupId> <groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId> <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> </dependency>
<!-- mybatis-spring --> <!-- mybatis-spring -->
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId> <artifactId>mybatis-spring</artifactId>
<version>1.2.2</version> <version>${mybatis-spring.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId> <artifactId>mybatis</artifactId>
<version>3.2.8</version> <version>${mybatis.version}</version>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency> </dependency>
<!-- httpclient --> <!-- httpclient -->
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
<version>4.3.6</version> <version>${httpclient.version}</version>
</dependency> </dependency>
<!-- javax.mail --> <!-- javax.mail -->
<dependency> <dependency>
<groupId>javax.mail</groupId> <groupId>javax.mail</groupId>
<artifactId>mail</artifactId> <artifactId>mail</artifactId>
<version>1.4.6</version> <version>${mail.version}</version>
</dependency> </dependency>
<!-- quartz :quartz-2.2.3/c3p0-0.9.1.1/slf4j-api-1.6.6 --> <!-- quartz :quartz-2.2.3/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
<dependency> <dependency>
<groupId>org.quartz-scheduler</groupId> <groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId> <artifactId>quartz</artifactId>
<version>2.3.0</version> <version>${quartz.version}</version>
</dependency> </dependency>
<!-- xxl-job-core --> <!-- xxl-job-core -->
......
package com.xxl.job.admin.controller; package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermessionLimit; 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.RpcRequest;
import com.xxl.job.core.rpc.codec.RpcResponse; import com.xxl.job.core.rpc.codec.RpcResponse;
import com.xxl.job.core.rpc.netcom.NetComServerFactory; import com.xxl.job.core.rpc.netcom.NetComServerFactory;
...@@ -46,7 +47,7 @@ public class JobApiController { ...@@ -46,7 +47,7 @@ public class JobApiController {
} }
} }
@RequestMapping("/api") @RequestMapping(AdminBiz.MAPPING)
@PermessionLimit(limit=false) @PermessionLimit(limit=false)
public void api(HttpServletRequest request, HttpServletResponse response) throws IOException { public void api(HttpServletRequest request, HttpServletResponse response) throws IOException {
......
...@@ -33,7 +33,7 @@ public class JobInfoController { ...@@ -33,7 +33,7 @@ public class JobInfoController {
private XxlJobService xxlJobService; private XxlJobService xxlJobService;
@RequestMapping @RequestMapping
public String index(Model model) { public String index(Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
// 枚举-字典 // 枚举-字典
model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表 model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表
...@@ -44,6 +44,8 @@ public class JobInfoController { ...@@ -44,6 +44,8 @@ public class JobInfoController {
// 任务组 // 任务组
List<XxlJobGroup> jobGroupList = xxlJobGroupDao.findAll(); List<XxlJobGroup> jobGroupList = xxlJobGroupDao.findAll();
model.addAttribute("JobGroupList", jobGroupList); model.addAttribute("JobGroupList", jobGroupList);
model.addAttribute("jobGroup", jobGroup);
return "jobinfo/jobinfo.index"; return "jobinfo/jobinfo.index";
} }
......
...@@ -3,6 +3,7 @@ package com.xxl.job.admin.controller; ...@@ -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.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.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.dao.XxlJobGroupDao; import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobLogDao;
...@@ -12,6 +13,8 @@ import com.xxl.job.core.biz.model.ReturnT; ...@@ -12,6 +13,8 @@ import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.rpc.netcom.NetComClientProxy; import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
...@@ -32,6 +35,7 @@ import java.util.Map; ...@@ -32,6 +35,7 @@ import java.util.Map;
@Controller @Controller
@RequestMapping("/joblog") @RequestMapping("/joblog")
public class JobLogController { public class JobLogController {
private static Logger logger = LoggerFactory.getLogger(JobLogController.class);
@Resource @Resource
private XxlJobGroupDao xxlJobGroupDao; private XxlJobGroupDao xxlJobGroupDao;
...@@ -116,7 +120,7 @@ public class JobLogController { ...@@ -116,7 +120,7 @@ public class JobLogController {
@ResponseBody @ResponseBody
public ReturnT<LogResult> logDetailCat(String executorAddress, long triggerTime, int logId, int fromLineNum){ public ReturnT<LogResult> logDetailCat(String executorAddress, long triggerTime, int logId, int fromLineNum){
try { try {
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, executorAddress).getObject(); ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(executorAddress);
ReturnT<LogResult> logResult = executorBiz.log(triggerTime, logId, fromLineNum); ReturnT<LogResult> logResult = executorBiz.log(triggerTime, logId, fromLineNum);
// is end // is end
...@@ -129,7 +133,7 @@ public class JobLogController { ...@@ -129,7 +133,7 @@ public class JobLogController {
return logResult; return logResult;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error(e.getMessage(), e);
return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage()); return new ReturnT<LogResult>(ReturnT.FAIL_CODE, e.getMessage());
} }
} }
...@@ -148,14 +152,14 @@ public class JobLogController { ...@@ -148,14 +152,14 @@ public class JobLogController {
} }
// request of kill // request of kill
ExecutorBiz executorBiz = null; ReturnT<String> runResult = null;
try { try {
executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, log.getExecutorAddress()).getObject(); ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(log.getExecutorAddress());
runResult = executorBiz.kill(jobInfo.getId());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); logger.error(e.getMessage(), e);
return new ReturnT<String>(500, e.getMessage()); runResult = new ReturnT<String>(500, e.getMessage());
} }
ReturnT<String> runResult = executorBiz.kill(jobInfo.getId());
if (ReturnT.SUCCESS_CODE == runResult.getCode()) { if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
log.setHandleCode(ReturnT.FAIL_CODE); log.setHandleCode(ReturnT.FAIL_CODE);
......
package com.xxl.job.admin.core.route; 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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -24,30 +22,4 @@ public abstract class ExecutorRouter { ...@@ -24,30 +22,4 @@ public abstract class ExecutorRouter {
*/ */
public abstract ReturnT<String> routeRun(TriggerParam triggerParam, ArrayList<String> addressList); 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; package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; 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.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -25,7 +26,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter { ...@@ -25,7 +26,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
// beat // beat
ReturnT<String> idleBeatResult = null; ReturnT<String> idleBeatResult = null;
try { try {
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject(); ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
idleBeatResult = executorBiz.idleBeat(triggerParam.getJobId()); idleBeatResult = executorBiz.idleBeat(triggerParam.getJobId());
} catch (Exception e) { } catch (Exception e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);
...@@ -40,7 +41,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter { ...@@ -40,7 +41,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
// beat success // beat success
if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) { 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()); idleBeatResultSB.append("<br><br>").append(runResult.getMsg());
// result // result
......
package com.xxl.job.admin.core.route.strategy; package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; 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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -82,7 +83,7 @@ public class ExecutorRouteConsistentHash extends ExecutorRouter { ...@@ -82,7 +83,7 @@ public class ExecutorRouteConsistentHash extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
// run executor // run executor
ReturnT<String> runResult = runExecutor(triggerParam, address); ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address); runResult.setContent(address);
return runResult; return runResult;
} }
......
package com.xxl.job.admin.core.route.strategy; package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; 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.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -25,7 +26,7 @@ public class ExecutorRouteFailover extends ExecutorRouter { ...@@ -25,7 +26,7 @@ public class ExecutorRouteFailover extends ExecutorRouter {
// beat // beat
ReturnT<String> beatResult = null; ReturnT<String> beatResult = null;
try { try {
ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address).getObject(); ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
beatResult = executorBiz.beat(); beatResult = executorBiz.beat();
} catch (Exception e) { } catch (Exception e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);
...@@ -40,7 +41,7 @@ public class ExecutorRouteFailover extends ExecutorRouter { ...@@ -40,7 +41,7 @@ public class ExecutorRouteFailover extends ExecutorRouter {
// beat success // beat success
if (beatResult.getCode() == ReturnT.SUCCESS_CODE) { 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()); beatResultSB.append("<br><br>").append(runResult.getMsg());
// result // result
......
package com.xxl.job.admin.core.route.strategy; 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.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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -23,7 +23,7 @@ public class ExecutorRouteFirst extends ExecutorRouter { ...@@ -23,7 +23,7 @@ public class ExecutorRouteFirst extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
// run executor // run executor
ReturnT<String> runResult = runExecutor(triggerParam, address); ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address); runResult.setContent(address);
return runResult; return runResult;
} }
......
package com.xxl.job.admin.core.route.strategy; package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; 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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -62,7 +63,7 @@ public class ExecutorRouteLFU extends ExecutorRouter { ...@@ -62,7 +63,7 @@ public class ExecutorRouteLFU extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
// run executor // run executor
ReturnT<String> runResult = runExecutor(triggerParam, address); ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address); runResult.setContent(address);
return runResult; return runResult;
} }
......
package com.xxl.job.admin.core.route.strategy; package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; 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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -61,7 +62,7 @@ public class ExecutorRouteLRU extends ExecutorRouter { ...@@ -61,7 +62,7 @@ public class ExecutorRouteLRU extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
// run executor // run executor
ReturnT<String> runResult = runExecutor(triggerParam, address); ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address); runResult.setContent(address);
return runResult; return runResult;
} }
......
package com.xxl.job.admin.core.route.strategy; 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.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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -22,7 +22,7 @@ public class ExecutorRouteLast extends ExecutorRouter { ...@@ -22,7 +22,7 @@ public class ExecutorRouteLast extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
// run executor // run executor
ReturnT<String> runResult = runExecutor(triggerParam, address); ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address); runResult.setContent(address);
return runResult; return runResult;
} }
......
package com.xxl.job.admin.core.route.strategy; package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; 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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -25,7 +26,7 @@ public class ExecutorRouteRandom extends ExecutorRouter { ...@@ -25,7 +26,7 @@ public class ExecutorRouteRandom extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
// run executor // run executor
ReturnT<String> runResult = runExecutor(triggerParam, address); ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address); runResult.setContent(address);
return runResult; return runResult;
} }
......
package com.xxl.job.admin.core.route.strategy; package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; 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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -41,7 +42,7 @@ public class ExecutorRouteRound extends ExecutorRouter { ...@@ -41,7 +42,7 @@ public class ExecutorRouteRound extends ExecutorRouter {
String address = route(triggerParam.getJobId(), addressList); String address = route(triggerParam.getJobId(), addressList);
// run executor // run executor
ReturnT<String> runResult = runExecutor(triggerParam, address); ReturnT<String> runResult = XxlJobTrigger.runExecutor(triggerParam, address);
runResult.setContent(address); runResult.setContent(address);
return runResult; return runResult;
} }
......
...@@ -9,62 +9,52 @@ import com.xxl.job.admin.dao.XxlJobInfoDao; ...@@ -9,62 +9,52 @@ import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.admin.dao.XxlJobRegistryDao; import com.xxl.job.admin.dao.XxlJobRegistryDao;
import com.xxl.job.core.biz.AdminBiz; import com.xxl.job.core.biz.AdminBiz;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import com.xxl.job.core.rpc.netcom.NetComServerFactory; import com.xxl.job.core.rpc.netcom.NetComServerFactory;
import org.quartz.*; import org.quartz.*;
import org.quartz.Trigger.TriggerState; import org.quartz.Trigger.TriggerState;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl; import org.quartz.impl.triggers.CronTriggerImpl;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import java.util.*; import java.util.Date;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* base quartz scheduler util * base quartz scheduler util
* @author xuxueli 2015-12-19 16:13:53 * @author xuxueli 2015-12-19 16:13:53
*/ */
public final class XxlJobDynamicScheduler implements ApplicationContextAware, InitializingBean { public final class XxlJobDynamicScheduler implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler.class); private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler.class);
// Scheduler // ---------------------- param ----------------------
// scheduler
private static Scheduler scheduler; private static Scheduler scheduler;
public void setScheduler(Scheduler scheduler) { public void setScheduler(Scheduler scheduler) {
XxlJobDynamicScheduler.scheduler = scheduler; XxlJobDynamicScheduler.scheduler = scheduler;
} }
// init
public void init() throws Exception {
// admin registry monitor run
JobRegistryMonitorHelper.getInstance().start();
// admin monitor run // accessToken
JobFailMonitorHelper.getInstance().start(); private static String accessToken;
public void setAccessToken(String accessToken) {
// rpc-service, base on spring-mvc this.accessToken = accessToken;
NetComServerFactory.putService(AdminBiz.class, XxlJobDynamicScheduler.adminBiz);
} }
// destroy
public void destroy(){
// admin registry stop
JobRegistryMonitorHelper.getInstance().toStop();
// admin monitor stop // dao
JobFailMonitorHelper.getInstance().toStop();
}
// xxlJobLogDao、xxlJobInfoDao
public static XxlJobLogDao xxlJobLogDao; public static XxlJobLogDao xxlJobLogDao;
public static XxlJobInfoDao xxlJobInfoDao; public static XxlJobInfoDao xxlJobInfoDao;
public static XxlJobRegistryDao xxlJobRegistryDao; public static XxlJobRegistryDao xxlJobRegistryDao;
public static XxlJobGroupDao xxlJobGroupDao; public static XxlJobGroupDao xxlJobGroupDao;
public static AdminBiz adminBiz; public static AdminBiz adminBiz;
// ---------------------- applicationContext ----------------------
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
XxlJobDynamicScheduler.xxlJobLogDao = applicationContext.getBean(XxlJobLogDao.class); XxlJobDynamicScheduler.xxlJobLogDao = applicationContext.getBean(XxlJobLogDao.class);
...@@ -73,48 +63,60 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In ...@@ -73,48 +63,60 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
XxlJobDynamicScheduler.xxlJobGroupDao = applicationContext.getBean(XxlJobGroupDao.class); XxlJobDynamicScheduler.xxlJobGroupDao = applicationContext.getBean(XxlJobGroupDao.class);
XxlJobDynamicScheduler.adminBiz = applicationContext.getBean(AdminBiz.class); XxlJobDynamicScheduler.adminBiz = applicationContext.getBean(AdminBiz.class);
} }
@Override // ---------------------- init + destroy ----------------------
public void afterPropertiesSet() throws Exception { public void init() throws Exception {
// admin registry monitor run
JobRegistryMonitorHelper.getInstance().start();
// admin monitor run
JobFailMonitorHelper.getInstance().start();
// admin-server(spring-mvc)
NetComServerFactory.putService(AdminBiz.class, XxlJobDynamicScheduler.adminBiz);
NetComServerFactory.setAccessToken(accessToken);
// valid
Assert.notNull(scheduler, "quartz scheduler is null"); Assert.notNull(scheduler, "quartz scheduler is null");
logger.info(">>>>>>>>> init quartz scheduler success.[{}]", scheduler); logger.info(">>>>>>>>> init quartz scheduler success.[{}]", scheduler);
} }
// getJobKeys public void destroy(){
@Deprecated // admin registry stop
public static List<Map<String, Object>> getJobList(){ JobRegistryMonitorHelper.getInstance().toStop();
List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();
// admin monitor stop
try { JobFailMonitorHelper.getInstance().toStop();
if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) { }
return null;
} // ---------------------- executor-client ----------------------
String groupName = scheduler.getJobGroupNames().get(0); private static ConcurrentHashMap<String, ExecutorBiz> executorBizRepository = new ConcurrentHashMap<String, ExecutorBiz>();
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName)); public static ExecutorBiz getExecutorBiz(String address) throws Exception {
if (jobKeys!=null && jobKeys.size()>0) { // valid
for (JobKey jobKey : jobKeys) { if (address==null || address.trim().length()==0) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP); return null;
Trigger trigger = scheduler.getTrigger(triggerKey); }
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
TriggerState triggerState = scheduler.getTriggerState(triggerKey); // load-cache
Map<String, Object> jobMap = new HashMap<String, Object>(); address = address.trim();
jobMap.put("TriggerKey", triggerKey); ExecutorBiz executorBiz = executorBizRepository.get(address);
jobMap.put("Trigger", trigger); if (executorBiz != null) {
jobMap.put("JobDetail", jobDetail); return executorBiz;
jobMap.put("TriggerState", triggerState); }
jobList.add(jobMap);
} // set-cache
} executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, address, accessToken).getObject();
executorBizRepository.put(address, executorBiz);
} catch (SchedulerException e) { return executorBiz;
e.printStackTrace(); }
return null;
} // ---------------------- schedule util ----------------------
return jobList;
} /**
* fill job info
// fill job info *
* @param jobInfo
*/
public static void fillJobInfo(XxlJobInfo jobInfo) { public static void fillJobInfo(XxlJobInfo jobInfo) {
// TriggerKey : name + group // TriggerKey : name + group
String group = String.valueOf(jobInfo.getJobGroup()); String group = String.valueOf(jobInfo.getJobGroup());
...@@ -145,14 +147,28 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In ...@@ -145,14 +147,28 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
} }
} }
// check if exists /**
* check if exists
*
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public static boolean checkExists(String jobName, String jobGroup) throws SchedulerException{ public static boolean checkExists(String jobName, String jobGroup) throws SchedulerException{
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
return scheduler.checkExists(triggerKey); return scheduler.checkExists(triggerKey);
} }
// addJob 新增 /**
@SuppressWarnings("unchecked") * addJob
*
* @param jobName
* @param jobGroup
* @param cronExpression
* @return
* @throws SchedulerException
*/
public static boolean addJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException { public static boolean addJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException {
// TriggerKey : name + group // TriggerKey : name + group
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
...@@ -185,7 +201,15 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In ...@@ -185,7 +201,15 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
return true; return true;
} }
// reschedule /**
* rescheduleJob
*
* @param jobGroup
* @param jobName
* @param cronExpression
* @return
* @throws SchedulerException
*/
public static boolean rescheduleJob(String jobGroup, String jobName, String cronExpression) throws SchedulerException { public static boolean rescheduleJob(String jobGroup, String jobName, String cronExpression) throws SchedulerException {
// TriggerKey valid if_exists // TriggerKey valid if_exists
...@@ -234,7 +258,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In ...@@ -234,7 +258,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
return true; return true;
} }
// unscheduleJob /**
* unscheduleJob
*
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public static boolean removeJob(String jobName, String jobGroup) throws SchedulerException { public static boolean removeJob(String jobName, String jobGroup) throws SchedulerException {
// TriggerKey : name + group // TriggerKey : name + group
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
...@@ -246,7 +277,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In ...@@ -246,7 +277,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
return true; return true;
} }
// Pause /**
* pause
*
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public static boolean pauseJob(String jobName, String jobGroup) throws SchedulerException { public static boolean pauseJob(String jobName, String jobGroup) throws SchedulerException {
// TriggerKey : name + group // TriggerKey : name + group
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
...@@ -262,7 +300,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In ...@@ -262,7 +300,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
return result; return result;
} }
// resume /**
* resume
*
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public static boolean resumeJob(String jobName, String jobGroup) throws SchedulerException { public static boolean resumeJob(String jobName, String jobGroup) throws SchedulerException {
// TriggerKey : name + group // TriggerKey : name + group
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
...@@ -278,7 +323,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In ...@@ -278,7 +323,14 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
return result; return result;
} }
// run /**
* run
*
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public static boolean triggerJob(String jobName, String jobGroup) throws SchedulerException { public static boolean triggerJob(String jobName, String jobGroup) throws SchedulerException {
// TriggerKey : name + group // TriggerKey : name + group
JobKey jobKey = new JobKey(jobName, jobGroup); JobKey jobKey = new JobKey(jobName, jobGroup);
...@@ -294,5 +346,41 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In ...@@ -294,5 +346,41 @@ public final class XxlJobDynamicScheduler implements ApplicationContextAware, In
return result; return result;
} }
/**
* finaAllJobList
*
* @return
*//*
@Deprecated
public static List<Map<String, Object>> finaAllJobList(){
List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();
try {
if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {
return null;
}
String groupName = scheduler.getJobGroupNames().get(0);
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
if (jobKeys!=null && jobKeys.size()>0) {
for (JobKey jobKey : jobKeys) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);
Trigger trigger = scheduler.getTrigger(triggerKey);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
TriggerState triggerState = scheduler.getTriggerState(triggerKey);
Map<String, Object> jobMap = new HashMap<String, Object>();
jobMap.put("TriggerKey", triggerKey);
jobMap.put("Trigger", trigger);
jobMap.put("JobDetail", jobDetail);
jobMap.put("TriggerState", triggerState);
jobList.add(jobMap);
}
}
} catch (SchedulerException e) {
e.printStackTrace();
return null;
}
return jobList;
}*/
} }
\ No newline at end of file
...@@ -30,7 +30,7 @@ public class JobFailMonitorHelper { ...@@ -30,7 +30,7 @@ public class JobFailMonitorHelper {
private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>(0xfff8); private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>(0xfff8);
private Thread monitorThread; private Thread monitorThread;
private boolean toStop = false; private volatile boolean toStop = false;
public void start(){ public void start(){
monitorThread = new Thread(new Runnable() { monitorThread = new Thread(new Runnable() {
......
...@@ -28,7 +28,7 @@ public class JobRegistryMonitorHelper { ...@@ -28,7 +28,7 @@ public class JobRegistryMonitorHelper {
} }
private Thread registryThread; private Thread registryThread;
private boolean toStop = false; private volatile boolean toStop = false;
public void start(){ public void start(){
registryThread = new Thread(new Runnable() { registryThread = new Thread(new Runnable() {
@Override @Override
......
...@@ -5,9 +5,9 @@ import com.xxl.job.admin.core.model.XxlJobGroup; ...@@ -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.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; 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.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.thread.JobFailMonitorHelper; 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.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
...@@ -90,12 +90,12 @@ public class XxlJobTrigger { ...@@ -90,12 +90,12 @@ public class XxlJobTrigger {
triggerParam.setBroadcastTotal(addressList.size()); // update02 triggerParam.setBroadcastTotal(addressList.size()); // update02
// 4.2、trigger-run (route run / trigger remote executor) // 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()); triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
// 4.3、trigger (fail retry) // 4.3、trigger (fail retry)
if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.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()); triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
} }
} }
...@@ -179,4 +179,30 @@ public class XxlJobTrigger { ...@@ -179,4 +179,30 @@ public class XxlJobTrigger {
logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId()); 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 @@ ...@@ -65,6 +65,7 @@
<bean id="xxlJobDynamicScheduler" class="com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler" init-method="init" destroy-method="destroy" > <bean id="xxlJobDynamicScheduler" class="com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler" init-method="init" destroy-method="destroy" >
<!-- (轻易不要变更“调度器名称”, 任务创建时会绑定该“调度器名称”) --> <!-- (轻易不要变更“调度器名称”, 任务创建时会绑定该“调度器名称”) -->
<property name="scheduler" ref="quartzScheduler"/> <property name="scheduler" ref="quartzScheduler"/>
<property name="accessToken" value="${xxl.job.accessToken}" />
</bean> </bean>
</beans> </beans>
\ No newline at end of file
...@@ -12,6 +12,9 @@ xxl.job.mail.password=asdfzxcv ...@@ -12,6 +12,9 @@ xxl.job.mail.password=asdfzxcv
xxl.job.mail.sendFrom=ovono802302@163.com xxl.job.mail.sendFrom=ovono802302@163.com
xxl.job.mail.sendNick=《任务调度平台XXL-JOB》 xxl.job.mail.sendNick=《任务调度平台XXL-JOB》
# xxl-job login ### xxl-job login
xxl.job.login.username=admin xxl.job.login.username=admin
xxl.job.login.password=123456 xxl.job.login.password=123456
\ No newline at end of file
### xxl-job, access token
xxl.job.accessToken=
\ No newline at end of file
...@@ -175,11 +175,12 @@ ...@@ -175,11 +175,12 @@
<#macro commonFooter > <#macro commonFooter >
<footer class="main-footer"> <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"> <div class="pull-right hidden-xs">
<strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp; <strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;
<a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>&nbsp; <a href="http://www.xuxueli.com/" target="_blank" >xuxueli</a>
<a href="http://my.oschina.net/xuxueli/blog/690978" target="_blank" >oschina</a> &nbsp;
<a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>
</strong><!-- All rights reserved. --> </strong><!-- All rights reserved. -->
</div> </div>
</footer> </footer>
......
...@@ -31,33 +31,14 @@ ...@@ -31,33 +31,14 @@
<h4>简介:XXL-JOB</h4> <h4>简介:XXL-JOB</h4>
<br> <br>
<p> <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> <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> <br><br>
<a target="_blank" href="http://my.oschina.net/xuxueli/blog/690978">oschina地址</a> <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)
<br><br> <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></p> <p></p>
</div> </div>
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
<span class="input-group-addon">执行器</span> <span class="input-group-addon">执行器</span>
<select class="form-control" id="jobGroup" > <select class="form-control" id="jobGroup" >
<#list JobGroupList as group> <#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> </#list>
</select> </select>
</div> </div>
...@@ -110,7 +110,7 @@ ...@@ -110,7 +110,7 @@
<div class="col-sm-4"> <div class="col-sm-4">
<select class="form-control" name="jobGroup" > <select class="form-control" name="jobGroup" >
<#list JobGroupList as group> <#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> </#list>
</select> </select>
</div> </div>
......
...@@ -167,6 +167,13 @@ $(function() { ...@@ -167,6 +167,13 @@ $(function() {
jobTable.fnDraw(); jobTable.fnDraw();
}); });
// jobGroup change
$('#jobGroup').on('change', function(){
//reload
var jobGroup = $('#jobGroup').val();
window.location.href = base_url + "/jobinfo?jobGroup=" + jobGroup;
});
// job operate // job operate
$("#job_list").on('click', '.job_operate',function() { $("#job_list").on('click', '.job_operate',function() {
var typeName; 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 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version> <version>1.8.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-core</artifactId> <artifactId>xxl-job-core</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
...@@ -13,56 +13,52 @@ ...@@ -13,56 +13,52 @@
<description>A lightweight distributed task scheduling framework.</description> <description>A lightweight distributed task scheduling framework.</description>
<url>http://www.xuxueli.com/</url> <url>http://www.xuxueli.com/</url>
<properties>
<spring.version>3.2.17.RELEASE</spring.version>
</properties>
<dependencies> <dependencies>
<!-- servlet --> <!-- servlet -->
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version> <version>${javax.servlet-api.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.servlet.jsp</groupId> <groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId> <artifactId>jsp-api</artifactId>
<version>2.2</version> <version>${jsp-api.version}</version>
</dependency> </dependency>
<!-- jetty --> <!-- jetty -->
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId> <artifactId>jetty-server</artifactId>
<version>9.2.21.v20170120</version> <version>${jetty-server.version}</version>
</dependency> </dependency>
<!-- slf4j --> <!-- slf4j -->
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>1.7.21</version> <version>${slf4j-api.version}</version>
</dependency> </dependency>
<!-- hessian --> <!-- hessian -->
<dependency> <dependency>
<groupId>com.caucho</groupId> <groupId>com.caucho</groupId>
<artifactId>hessian</artifactId> <artifactId>hessian</artifactId>
<version>4.0.38</version> <version>${hessian.version}</version>
</dependency> </dependency>
<!-- jackson --> <!-- jackson -->
<dependency> <dependency>
<groupId>org.codehaus.jackson</groupId> <groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId> <artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version> <version>${jackson-mapper-asl.version}</version>
</dependency> </dependency>
<!-- httpclient --> <!-- httpclient -->
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
<version>4.3.6</version> <version>${httpclient.version}</version>
</dependency> </dependency>
<!-- spring-context --> <!-- spring-context -->
...@@ -76,14 +72,14 @@ ...@@ -76,14 +72,14 @@
<dependency> <dependency>
<groupId>org.codehaus.groovy</groupId> <groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId> <artifactId>groovy-all</artifactId>
<version>2.4.5</version> <version>${groovy-all.version}</version>
</dependency> </dependency>
<!-- commons-exec --> <!-- commons-exec -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId> <artifactId>commons-exec</artifactId>
<version>1.3</version> <version>${commons-exec.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
......
...@@ -11,6 +11,8 @@ import java.util.List; ...@@ -11,6 +11,8 @@ import java.util.List;
*/ */
public interface AdminBiz { public interface AdminBiz {
public static final String MAPPING = "/api";
/** /**
* callback * callback
* *
......
package com.xxl.job.core.executor; 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.ExecutorBiz;
import com.xxl.job.core.biz.impl.ExecutorBizImpl; import com.xxl.job.core.biz.impl.ExecutorBizImpl;
import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.JobHander; 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.rpc.netcom.NetComServerFactory;
import com.xxl.job.core.thread.ExecutorRegistryThread;
import com.xxl.job.core.thread.JobThread; import com.xxl.job.core.thread.JobThread;
import com.xxl.job.core.thread.TriggerCallbackThread;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; 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.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* Created by xuxueli on 2016/3/2 21:14. * 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); private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);
// ---------------------- param ----------------------
private String ip; private String ip;
private int port = 9999; private int port = 9999;
private String appName; private String appName;
public static String adminAddresses; private String adminAddresses;
public static String logPath; private String accessToken;
private String logPath;
public void setIp(String ip) { public void setIp(String ip) {
this.ip = ip; this.ip = ip;
...@@ -44,48 +46,98 @@ public class XxlJobExecutor implements ApplicationContextAware, ApplicationListe ...@@ -44,48 +46,98 @@ public class XxlJobExecutor implements ApplicationContextAware, ApplicationListe
public void setAdminAddresses(String adminAddresses) { public void setAdminAddresses(String adminAddresses) {
this.adminAddresses = adminAddresses; this.adminAddresses = adminAddresses;
} }
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public void setLogPath(String logPath) { public void setLogPath(String logPath) {
this.logPath = 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 // ---------------------- applicationContext ----------------------
TriggerCallbackThread.getInstance().start(); private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
} }
public void destroy(){ public static ApplicationContext getApplicationContext() {
// 1、executor registry thread stop return applicationContext;
ExecutorRegistryThread.getInstance().toStop(); }
// ---------------------- start + stop ----------------------
public void start() throws Exception {
// init admin-client
initAdminBizList(adminAddresses, accessToken);
// init executor-jobHandlerRepository
initJobHandlerRepository(applicationContext);
// 2、executor stop // init logpath
serverFactory.destroy(); 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) { if (JobThreadRepository.size() > 0) {
for (Map.Entry<Integer, JobThread> item: JobThreadRepository.entrySet()) { for (Map.Entry<Integer, JobThread> item: JobThreadRepository.entrySet()) {
JobThread jobThread = item.getValue(); removeJobThread(item.getKey(), "Web容器销毁终止");
jobThread.toStop("Web容器销毁终止");
jobThread.interrupt();
} }
JobThreadRepository.clear(); JobThreadRepository.clear();
} }
// 4、trigger callback thread stop // destory executor-server
TriggerCallbackThread.getInstance().toStop(); 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 // init job handler action
Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHander.class); Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHander.class);
...@@ -101,27 +153,10 @@ public class XxlJobExecutor implements ApplicationContextAware, ApplicationListe ...@@ -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>(); private static ConcurrentHashMap<Integer, JobThread> JobThreadRepository = new ConcurrentHashMap<Integer, JobThread>();
public static JobThread registJobThread(int jobId, IJobHandler handler, String removeOldReason){ public static JobThread registJobThread(int jobId, IJobHandler handler, String removeOldReason){
JobThread newJobThread = new JobThread(jobId, handler); JobThread newJobThread = new JobThread(jobId, handler);
......
...@@ -52,21 +52,21 @@ public class GlueFactory { ...@@ -52,21 +52,21 @@ public class GlueFactory {
try { try {
Resource resource = AnnotationUtils.getAnnotation(field, Resource.class); Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);
if (resource.name()!=null && resource.name().length()>0){ if (resource.name()!=null && resource.name().length()>0){
fieldBean = XxlJobExecutor.applicationContext.getBean(resource.name()); fieldBean = XxlJobExecutor.getApplicationContext().getBean(resource.name());
} else { } else {
fieldBean = XxlJobExecutor.applicationContext.getBean(field.getName()); fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getName());
} }
} catch (Exception e) { } catch (Exception e) {
} }
if (fieldBean==null ) { if (fieldBean==null ) {
fieldBean = XxlJobExecutor.applicationContext.getBean(field.getType()); fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getType());
} }
} else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) { } else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) {
Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class); Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class);
if (qualifier!=null && qualifier.value()!=null && qualifier.value().length()>0) { if (qualifier!=null && qualifier.value()!=null && qualifier.value().length()>0) {
fieldBean = XxlJobExecutor.applicationContext.getBean(qualifier.value()); fieldBean = XxlJobExecutor.getApplicationContext().getBean(qualifier.value());
} else { } else {
fieldBean = XxlJobExecutor.applicationContext.getBean(field.getType()); fieldBean = XxlJobExecutor.getApplicationContext().getBean(field.getType());
} }
} }
......
package com.xxl.job.core.handler.impl; package com.xxl.job.core.handler.impl;
import com.xxl.job.core.biz.model.ReturnT; 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.glue.GlueTypeEnum;
import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.log.XxlJobFileAppender; import com.xxl.job.core.log.XxlJobFileAppender;
...@@ -37,17 +36,17 @@ public class ScriptJobHandler extends IJobHandler { ...@@ -37,17 +36,17 @@ public class ScriptJobHandler extends IJobHandler {
String scriptFileName = null; String scriptFileName = null;
if (GlueTypeEnum.GLUE_SHELL == glueType) { if (GlueTypeEnum.GLUE_SHELL == glueType) {
cmd = "bash"; 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) { } else if (GlueTypeEnum.GLUE_PYTHON == glueType) {
cmd = "python"; 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 // make script file
ScriptUtil.markScriptFile(scriptFileName, gluesource); ScriptUtil.markScriptFile(scriptFileName, gluesource);
// log file // log file
String logFileName = XxlJobExecutor.logPath.concat(XxlJobFileAppender.contextHolder.get()); String logFileName = XxlJobFileAppender.logPath.concat(XxlJobFileAppender.contextHolder.get());
// invoke // invoke
XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------"); XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------");
......
package com.xxl.job.core.log; package com.xxl.job.core.log;
import com.xxl.job.core.biz.model.LogResult; import com.xxl.job.core.biz.model.LogResult;
import com.xxl.job.core.executor.XxlJobExecutor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -20,7 +19,8 @@ public class XxlJobFileAppender { ...@@ -20,7 +19,8 @@ public class XxlJobFileAppender {
//public static ThreadLocal<String> contextHolder = new ThreadLocal<String>(); //public static ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static final InheritableThreadLocal<String> contextHolder = new InheritableThreadLocal<String>(); public static final InheritableThreadLocal<String> contextHolder = new InheritableThreadLocal<String>();
public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 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 * log filename: yyyy-MM-dd/9999.log
* *
...@@ -31,7 +31,7 @@ public class XxlJobFileAppender { ...@@ -31,7 +31,7 @@ public class XxlJobFileAppender {
public static String makeLogFileName(Date triggerDate, int logId) { public static String makeLogFileName(Date triggerDate, int logId) {
// filePath/ // filePath/
File filePathDir = new File(XxlJobExecutor.logPath); File filePathDir = new File(logPath);
if (!filePathDir.exists()) { if (!filePathDir.exists()) {
filePathDir.mkdirs(); filePathDir.mkdirs();
} }
...@@ -66,7 +66,7 @@ public class XxlJobFileAppender { ...@@ -66,7 +66,7 @@ public class XxlJobFileAppender {
if (logFileName==null || logFileName.trim().length()==0) { if (logFileName==null || logFileName.trim().length()==0) {
return; return;
} }
File logFile = new File(XxlJobExecutor.logPath, logFileName); File logFile = new File(logPath, logFileName);
if (!logFile.exists()) { if (!logFile.exists()) {
try { try {
...@@ -111,7 +111,7 @@ public class XxlJobFileAppender { ...@@ -111,7 +111,7 @@ public class XxlJobFileAppender {
if (logFileName==null || logFileName.trim().length()==0) { if (logFileName==null || logFileName.trim().length()==0) {
return new LogResult(fromLineNum, 0, "readLog fail, logFile not found", true); 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()) { if (!logFile.exists()) {
return new LogResult(fromLineNum, 0, "readLog fail, logFile not exists", true); return new LogResult(fromLineNum, 0, "readLog fail, logFile not exists", true);
......
...@@ -12,12 +12,14 @@ public class RpcRequest implements Serializable{ ...@@ -12,12 +12,14 @@ public class RpcRequest implements Serializable{
private String serverAddress; private String serverAddress;
private long createMillisTime; private long createMillisTime;
private String accessToken;
private String className; private String className;
private String methodName; private String methodName;
private Class<?>[] parameterTypes; private Class<?>[] parameterTypes;
private Object[] parameters; private Object[] parameters;
public String getServerAddress() { public String getServerAddress() {
return serverAddress; return serverAddress;
} }
...@@ -29,41 +31,62 @@ public class RpcRequest implements Serializable{ ...@@ -29,41 +31,62 @@ public class RpcRequest implements Serializable{
public long getCreateMillisTime() { public long getCreateMillisTime() {
return createMillisTime; return createMillisTime;
} }
public void setCreateMillisTime(long createMillisTime) { public void setCreateMillisTime(long createMillisTime) {
this.createMillisTime = createMillisTime; this.createMillisTime = createMillisTime;
} }
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getClassName() { public String getClassName() {
return className; return className;
} }
public void setClassName(String className) { public void setClassName(String className) {
this.className = className; this.className = className;
} }
public String getMethodName() { public String getMethodName() {
return methodName; return methodName;
} }
public void setMethodName(String methodName) { public void setMethodName(String methodName) {
this.methodName = methodName; this.methodName = methodName;
} }
public Class<?>[] getParameterTypes() { public Class<?>[] getParameterTypes() {
return parameterTypes; return parameterTypes;
} }
public void setParameterTypes(Class<?>[] parameterTypes) { public void setParameterTypes(Class<?>[] parameterTypes) {
this.parameterTypes = parameterTypes; this.parameterTypes = parameterTypes;
} }
public Object[] getParameters() { public Object[] getParameters() {
return parameters; return parameters;
} }
public void setParameters(Object[] parameters) { public void setParameters(Object[] parameters) {
this.parameters = parameters; this.parameters = parameters;
} }
@Override @Override
public String toString() { public String toString() {
return "NettyRequest [serverAddress=" + serverAddress + ", createMillisTime=" return "RpcRequest{" +
+ createMillisTime + ", className=" + className "serverAddress='" + serverAddress + '\'' +
+ ", methodName=" + methodName + ", parameterTypes=" ", createMillisTime=" + createMillisTime +
+ Arrays.toString(parameterTypes) + ", parameters=" ", accessToken='" + accessToken + '\'' +
+ Arrays.toString(parameters) + "]"; ", className='" + className + '\'' +
", methodName='" + methodName + '\'' +
", parameterTypes=" + Arrays.toString(parameterTypes) +
", parameters=" + Arrays.toString(parameters) +
'}';
} }
} }
...@@ -20,11 +20,13 @@ public class NetComClientProxy implements FactoryBean<Object> { ...@@ -20,11 +20,13 @@ public class NetComClientProxy implements FactoryBean<Object> {
// ---------------------- config ---------------------- // ---------------------- config ----------------------
private Class<?> iface; private Class<?> iface;
String serverAddress; private String serverAddress;
JettyClient client = new JettyClient(); private String accessToken;
public NetComClientProxy(Class<?> iface, String serverAddress) { private JettyClient client = new JettyClient();
public NetComClientProxy(Class<?> iface, String serverAddress, String accessToken) {
this.iface = iface; this.iface = iface;
this.serverAddress = serverAddress; this.serverAddress = serverAddress;
this.accessToken = accessToken;
} }
@Override @Override
...@@ -39,6 +41,7 @@ public class NetComClientProxy implements FactoryBean<Object> { ...@@ -39,6 +41,7 @@ public class NetComClientProxy implements FactoryBean<Object> {
RpcRequest request = new RpcRequest(); RpcRequest request = new RpcRequest();
request.setServerAddress(serverAddress); request.setServerAddress(serverAddress);
request.setCreateMillisTime(System.currentTimeMillis()); request.setCreateMillisTime(System.currentTimeMillis());
request.setAccessToken(accessToken);
request.setClassName(method.getDeclaringClass().getName()); request.setClassName(method.getDeclaringClass().getName());
request.setMethodName(method.getName()); request.setMethodName(method.getName());
request.setParameterTypes(method.getParameterTypes()); request.setParameterTypes(method.getParameterTypes());
......
...@@ -30,14 +30,18 @@ public class NetComServerFactory { ...@@ -30,14 +30,18 @@ public class NetComServerFactory {
server.destroy(); server.destroy();
} }
// ---------------------- server init ---------------------- // ---------------------- server instance ----------------------
/** /**
* init local rpc service map * init local rpc service map
*/ */
private static Map<String, Object> serviceMap = new HashMap<String, Object>(); private static Map<String, Object> serviceMap = new HashMap<String, Object>();
private static String accessToken;
public static void putService(Class<?> iface, Object serviceBean){ public static void putService(Class<?> iface, Object serviceBean){
serviceMap.put(iface.getName(), serviceBean); serviceMap.put(iface.getName(), serviceBean);
} }
public static void setAccessToken(String accessToken) {
NetComServerFactory.accessToken = accessToken;
}
public static RpcResponse invokeService(RpcRequest request, Object serviceBean) { public static RpcResponse invokeService(RpcRequest request, Object serviceBean) {
if (serviceBean==null) { if (serviceBean==null) {
serviceBean = serviceMap.get(request.getClassName()); serviceBean = serviceMap.get(request.getClassName());
...@@ -49,7 +53,11 @@ public class NetComServerFactory { ...@@ -49,7 +53,11 @@ public class NetComServerFactory {
RpcResponse response = new RpcResponse(); RpcResponse response = new RpcResponse();
if (System.currentTimeMillis() - request.getCreateMillisTime() > 180000) { 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; return response;
} }
......
...@@ -21,8 +21,8 @@ public class JettyClient { ...@@ -21,8 +21,8 @@ public class JettyClient {
// reqURL // reqURL
String reqURL = request.getServerAddress(); String reqURL = request.getServerAddress();
if (reqURL!=null && reqURL.toLowerCase().indexOf("http://")==-1) { if (reqURL!=null && reqURL.toLowerCase().indexOf("http")==-1) {
reqURL = "http://" + request.getServerAddress() + "/"; reqURL = "http://" + request.getServerAddress() + "/"; // IP:PORT, need parse to url
} }
// remote invoke // remote invoke
......
package com.xxl.job.core.rpc.netcom.jetty.server; package com.xxl.job.core.rpc.netcom.jetty.server;
import com.xxl.job.core.thread.ExecutorRegistryThread; 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.Connector;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
...@@ -38,10 +39,16 @@ public class JettyServer { ...@@ -38,10 +39,16 @@ public class JettyServer {
server.setHandler(handlerc); server.setHandler(handlerc);
try { try {
// Start the server // Start server
server.start(); server.start();
logger.info(">>>>>>>>>>>> xxl-job jetty server start success at port:{}.", port); logger.info(">>>>>>>>>>>> xxl-job jetty server start success at port:{}.", port);
// Start Registry-Server
ExecutorRegistryThread.getInstance().start(port, ip, appName); ExecutorRegistryThread.getInstance().start(port, ip, appName);
// Start Callback-Server
TriggerCallbackThread.getInstance().start();
server.join(); // block until thread stopped server.join(); // block until thread stopped
logger.info(">>>>>>>>>>> xxl-rpc server join success, netcon={}, port={}", JettyServer.class.getName(), port); logger.info(">>>>>>>>>>> xxl-rpc server join success, netcon={}, port={}", JettyServer.class.getName(), port);
} catch (Exception e) { } catch (Exception e) {
...@@ -56,6 +63,8 @@ public class JettyServer { ...@@ -56,6 +63,8 @@ public class JettyServer {
} }
public void destroy() { public void destroy() {
// destroy server
if (server != null) { if (server != null) {
try { try {
server.stop(); server.stop();
...@@ -67,6 +76,13 @@ public class JettyServer { ...@@ -67,6 +76,13 @@ public class JettyServer {
if (thread.isAlive()) { if (thread.isAlive()) {
thread.interrupt(); 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()); logger.info(">>>>>>>>>>> xxl-rpc server destroy success, netcon={}", JettyServer.class.getName());
} }
......
...@@ -5,7 +5,6 @@ import com.xxl.job.core.biz.model.RegistryParam; ...@@ -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.biz.model.ReturnT;
import com.xxl.job.core.enums.RegistryConfig; import com.xxl.job.core.enums.RegistryConfig;
import com.xxl.job.core.executor.XxlJobExecutor; import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import com.xxl.job.core.util.IpUtil; import com.xxl.job.core.util.IpUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -32,7 +31,7 @@ public class ExecutorRegistryThread extends Thread { ...@@ -32,7 +31,7 @@ public class ExecutorRegistryThread extends Thread {
logger.warn(">>>>>>>>>>>> xxl-job, executor registry config fail, appName is null."); logger.warn(">>>>>>>>>>>> xxl-job, executor registry config fail, appName is null.");
return; 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."); logger.warn(">>>>>>>>>>>> xxl-job, executor registry config fail, adminAddresses is null.");
return; return;
} }
...@@ -49,15 +48,10 @@ public class ExecutorRegistryThread extends Thread { ...@@ -49,15 +48,10 @@ public class ExecutorRegistryThread extends Thread {
@Override @Override
public void run() { public void run() {
while (!toStop) { while (!toStop) {
try { try {
RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, executorAddress); RegistryParam registryParam = new RegistryParam(RegistryConfig.RegistType.EXECUTOR.name(), appName, executorAddress);
for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
for (String addressUrl: XxlJobExecutor.adminAddresses.split(",")) {
String apiUrl = addressUrl.concat("/api");
try { try {
AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, apiUrl).getObject();
ReturnT<String> registryResult = adminBiz.registry(registryParam); ReturnT<String> registryResult = adminBiz.registry(registryParam);
if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) { if (registryResult!=null && ReturnT.SUCCESS_CODE == registryResult.getCode()) {
registryResult = ReturnT.SUCCESS; registryResult = ReturnT.SUCCESS;
...@@ -71,7 +65,6 @@ public class ExecutorRegistryThread extends Thread { ...@@ -71,7 +65,6 @@ public class ExecutorRegistryThread extends Thread {
} }
} }
} catch (Exception e) { } catch (Exception e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);
} }
......
...@@ -4,7 +4,6 @@ import com.xxl.job.core.biz.AdminBiz; ...@@ -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.HandleCallbackParam;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.executor.XxlJobExecutor; import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -43,17 +42,14 @@ public class TriggerCallbackThread { ...@@ -43,17 +42,14 @@ public class TriggerCallbackThread {
callbackParamList.add(callback); callbackParamList.add(callback);
// valid // 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); logger.warn(">>>>>>>>>>>> xxl-job callback fail, adminAddresses is null, callbackParamList:{}", callbackParamList);
continue; continue;
} }
// callback, will retry if error // callback, will retry if error
for (String addressUrl: XxlJobExecutor.adminAddresses.split(",")) { for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {
String apiUrl = addressUrl.concat("/api");
try { try {
AdminBiz adminBiz = (AdminBiz) new NetComClientProxy(AdminBiz.class, apiUrl).getObject();
ReturnT<String> callbackResult = adminBiz.callback(callbackParamList); ReturnT<String> callbackResult = adminBiz.callback(callbackParamList);
if (callbackResult!=null && ReturnT.SUCCESS_CODE == callbackResult.getCode()) { if (callbackResult!=null && ReturnT.SUCCESS_CODE == callbackResult.getCode()) {
callbackResult = ReturnT.SUCCESS; callbackResult = ReturnT.SUCCESS;
......
package com.xxl.job.core.util; 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.CommandLine;
import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler; import org.apache.commons.exec.PumpStreamHandler;
...@@ -28,7 +28,7 @@ public class ScriptUtil { ...@@ -28,7 +28,7 @@ public class ScriptUtil {
*/ */
public static void markScriptFile(String scriptFileName, String content) throws IOException { public static void markScriptFile(String scriptFileName, String content) throws IOException {
// filePath/ // filePath/
File filePathDir = new File(XxlJobExecutor.logPath); File filePathDir = new File(XxlJobFileAppender.logPath);
if (!filePathDir.exists()) { if (!filePathDir.exists()) {
filePathDir.mkdirs(); filePathDir.mkdirs();
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version> <version>1.8.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-executor-example</artifactId> <artifactId>xxl-job-executor-example</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
...@@ -13,12 +13,8 @@ ...@@ -13,12 +13,8 @@
<description>Executor project for spring boot.</description> <description>Executor project for spring boot.</description>
<url>http://www.xuxueli.com/</url> <url>http://www.xuxueli.com/</url>
<properties>
<spring.version>3.2.17.RELEASE</spring.version>
</properties>
<dependencies> <dependencies>
<!-- springframe start --> <!-- spring-webmvc -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId> <artifactId>spring-webmvc</artifactId>
...@@ -29,20 +25,7 @@ ...@@ -29,20 +25,7 @@
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId> <artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version> <version>${slf4j-api.version}</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>
</dependency> </dependency>
<!-- xxl-job-core --> <!-- xxl-job-core -->
...@@ -51,7 +34,6 @@ ...@@ -51,7 +34,6 @@
<artifactId>xxl-job-core</artifactId> <artifactId>xxl-job-core</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
<property name="adminAddresses" value="${xxl.job.admin.addresses}" /> <property name="adminAddresses" value="${xxl.job.admin.addresses}" />
<!-- 执行器日志路径[必填] --> <!-- 执行器日志路径[必填] -->
<property name="logPath" value="${xxl.job.executor.logpath}" /> <property name="logPath" value="${xxl.job.executor.logpath}" />
<!-- 访问令牌,非空则进行匹配校验[选填] -->
<property name="accessToken" value="${xxl.job.accessToken}" />
</bean> </bean>
......
...@@ -7,4 +7,7 @@ xxl.job.executor.ip= ...@@ -7,4 +7,7 @@ xxl.job.executor.ip=
xxl.job.executor.port=9999 xxl.job.executor.port=9999
### xxl-job log path ### xxl-job log path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/ xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
\ No newline at end of file
### xxl-job, access token
xxl.job.accessToken=
\ No newline at end of file
...@@ -8,6 +8,8 @@ import com.xxl.job.core.glue.GlueTypeEnum; ...@@ -8,6 +8,8 @@ import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.rpc.netcom.NetComClientProxy; import com.xxl.job.core.rpc.netcom.NetComClientProxy;
/** /**
* executor-api client, test
*
* Created by xuxueli on 17/5/12. * Created by xuxueli on 17/5/12.
*/ */
public class DemoJobHandlerTest { public class DemoJobHandlerTest {
...@@ -31,7 +33,8 @@ public class DemoJobHandlerTest { ...@@ -31,7 +33,8 @@ public class DemoJobHandlerTest {
triggerParam.setLogDateTim(System.currentTimeMillis()); triggerParam.setLogDateTim(System.currentTimeMillis());
// do remote trigger // 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); ReturnT<String> runResult = executorBiz.run(triggerParam);
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.8.1-SNAPSHOT</version> <version>1.8.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-executor-springboot-example</artifactId> <artifactId>xxl-job-executor-springboot-example</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
<url>http://www.xuxueli.com/</url> <url>http://www.xuxueli.com/</url>
<properties> <properties>
<spring-boot.version>1.3.8.RELEASE</spring-boot.version>
<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>
<java.version>1.7</java.version> <java.version>1.7</java.version>
...@@ -33,41 +31,44 @@ ...@@ -33,41 +31,44 @@
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </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> </dependencies>
</dependencyManagement> </dependencyManagement>
<dependencies> <dependencies>
<!-- spring-boot-starter-web (spring-webmvc + tomcat) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- spring-boot-starter-web (提供了对web的支持,包含了spring webmvc和tomcat等web开发的特性) -->
<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>
<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>
<!-- 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 --> <!-- xxl-job-core -->
<dependency> <dependency>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
......
...@@ -34,6 +34,8 @@ public class XxlJobConfig { ...@@ -34,6 +34,8 @@ public class XxlJobConfig {
@Value("${xxl.job.executor.logpath}") @Value("${xxl.job.executor.logpath}")
private String logpath; private String logpath;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Bean(initMethod = "start", destroyMethod = "destroy") @Bean(initMethod = "start", destroyMethod = "destroy")
public XxlJobExecutor xxlJobExecutor() { public XxlJobExecutor xxlJobExecutor() {
...@@ -44,6 +46,7 @@ public class XxlJobConfig { ...@@ -44,6 +46,7 @@ public class XxlJobConfig {
xxlJobExecutor.setAppName(appname); xxlJobExecutor.setAppName(appname);
xxlJobExecutor.setAdminAddresses(addresses); xxlJobExecutor.setAdminAddresses(addresses);
xxlJobExecutor.setLogPath(logpath); xxlJobExecutor.setLogPath(logpath);
xxlJobExecutor.setAccessToken(accessToken);
return xxlJobExecutor; return xxlJobExecutor;
} }
......
...@@ -15,3 +15,6 @@ xxl.job.executor.port=9998 ...@@ -15,3 +15,6 @@ xxl.job.executor.port=9998
### xxl-job log path ### xxl-job log path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/ xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
### xxl-job, access token
xxl.job.accessToken=
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册