diff --git a/README.md b/README.md index c7d33de2..802d8ddb 100644 --- a/README.md +++ b/README.md @@ -47,29 +47,30 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ## Features - 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; - 2、动态:支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,即时生效; -- 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现,可保证调度中心HA; +- 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现并支持集群部署,可保证调度中心HA; - 4、执行器HA(分布式):任务分布式执行,任务"执行器"支持集群部署,可保证任务执行HA; -- 5、任务Failover:执行器集群部署时,任务路由策略选择"故障转移"情况下调度失败时将会平滑切换执行器进行Failover; -- 6、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行; -- 7、自定义任务参数:支持在线配置调度任务入参,即时生效; -- 8、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞; -- 9、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务; -- 10、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件; -- 11、状态监控:支持实时监控任务进度; -- 12、Rolling执行日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志; -- 13、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。 -- 14、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性; -- 15、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔; -- 16、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用; -- 17、任务注册: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址; -- 18、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等; -- 19、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等; -- 20、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python等类型脚本; -- 21、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度; -- 22、失败处理策略;调度失败时的处理策略,策略包括:失败告警(默认)、失败重试; -- 23、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发对应集群中所有执行器执行一次任务,同时传递分片参数;可根据分片参数开发分片任务; -- 24、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 -- 25、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。 +- 5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址; +- 6、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务; +- 7、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等; +- 8、故障转移:任务路由策略选择"故障转移"情况下,如果执行器集群中某一台机器故障,将会自动Failover切换到一台正常的执行器发送调度请求。 +- 9、失败处理策略;调度失败时的处理策略,策略包括:失败告警(默认)、失败重试; +- 10、失败重试:调度中心调度失败且启用"失败重试"策略时,将会自动重试一次;执行器执行失败且回调失败重试状态时,也将会自动重试一次; +- 11、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度; +- 12、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务; +- 13、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 +- 14、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。 +- 15、任务进度监控:支持实时监控任务进度; +- 16、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志; +- 17、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。 +- 18、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS等类型脚本; +- 19、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔; +- 20、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行; +- 21、自定义任务参数:支持在线配置调度任务入参,即时生效; +- 22、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞; +- 23、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性; +- 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件; +- 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用; +- 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等; ## Development @@ -83,8 +84,10 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 于2017-05-13,在上海举办的 "[第62期开源中国源创会](https://www.oschina.net/event/2236961)" 的 "放码过来" 环节,我登台对XXL-JOB做了演讲,台下五百位在场观众反响热烈([图文回顾](https://www.oschina.net/question/2686220_2242120) )。 +于2017-12-11,XXL-JOB有幸参会《[InfoQ ArchSummit全球架构师峰会](http://bj2017.archsummit.com/)》,并被拍拍贷架构总监"杨波老师"在专题 "[微服务原理、基础架构和开源实践](http://bj2017.archsummit.com/training/2)" 中现场介绍。 + > 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。** -据最新统计, 自2016-01-21接入至2017-07-07期间,该系统已调度约60万余次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。 +据最新统计, 自2016-01-21接入至2017-12-01期间,该系统已调度约100万次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。 至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止2016-07-19为止,XXL-JOB已接入的公司包括不限于: @@ -145,6 +148,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 - 55、中商惠民(北京)电子商务有限公司 - 56、凯京集团 - 57、华夏票联(北京)科技有限公司 + - 58、拍拍贷 + - 59、北京尚德机构在线教育有限公司 - …… > 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。 diff --git a/doc/XXL-JOB官方文档.md b/doc/XXL-JOB官方文档.md index a05fe3f9..d2aaa475 100644 --- a/doc/XXL-JOB官方文档.md +++ b/doc/XXL-JOB官方文档.md @@ -16,29 +16,30 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ### 1.2 特性 - 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; - 2、动态:支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,即时生效; -- 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现,可保证调度中心HA; +- 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现并支持集群部署,可保证调度中心HA; - 4、执行器HA(分布式):任务分布式执行,任务"执行器"支持集群部署,可保证任务执行HA; -- 5、任务Failover:执行器集群部署时,任务路由策略选择"故障转移"情况下调度失败时将会平滑切换执行器进行Failover; -- 6、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行; -- 7、自定义任务参数:支持在线配置调度任务入参,即时生效; -- 8、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞; -- 9、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务; -- 10、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件; -- 11、状态监控:支持实时监控任务进度; -- 12、Rolling执行日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志; -- 13、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。 -- 14、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性; -- 15、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔; -- 16、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用; -- 17、任务注册: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址; -- 18、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等; -- 19、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等; -- 20、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python等类型脚本; -- 21、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度; -- 22、失败处理策略;调度失败时的处理策略,策略包括:失败告警(默认)、失败重试; -- 23、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务; -- 24、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 -- 25、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。 +- 5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址; +- 6、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务; +- 7、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等; +- 8、故障转移:任务路由策略选择"故障转移"情况下,如果执行器集群中某一台机器故障,将会自动Failover切换到一台正常的执行器发送调度请求。 +- 9、失败处理策略;调度失败时的处理策略,策略包括:失败告警(默认)、失败重试; +- 10、失败重试:调度中心调度失败且启用"失败重试"策略时,将会自动重试一次;执行器执行失败且回调失败重试状态时,也将会自动重试一次; +- 11、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度; +- 12、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务; +- 13、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 +- 14、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。 +- 15、任务进度监控:支持实时监控任务进度; +- 16、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志; +- 17、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。 +- 18、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS等类型脚本; +- 19、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔; +- 20、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行; +- 21、自定义任务参数:支持在线配置调度任务入参,即时生效; +- 22、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞; +- 23、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性; +- 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件; +- 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用; +- 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等; ### 1.3 发展 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计…… @@ -51,8 +52,10 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 于2017-05-13,在上海举办的 "[第62期开源中国源创会](https://www.oschina.net/event/2236961)" 的 "放码过来" 环节,我登台对XXL-JOB做了演讲,台下五百位在场观众反响热烈([图文回顾](https://www.oschina.net/question/2686220_2242120) )。 +于2017-12-11,XXL-JOB有幸参会《[InfoQ ArchSummit全球架构师峰会](http://bj2017.archsummit.com/)》,并被拍拍贷架构总监"杨波老师"在专题 "[微服务原理、基础架构和开源实践](http://bj2017.archsummit.com/training/2)" 中现场介绍。 + > 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。 -据最新统计, 自2016-01-21接入至2017-07-07期间,该系统已调度约60万余次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。 +据最新统计, 自2016-01-21接入至2017-12-01期间,该系统已调度约100万次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。 至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止2016-07-19为止,XXL-JOB已接入的公司包括不限于: @@ -113,6 +116,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 - 55、中商惠民(北京)电子商务有限公司 - 56、凯京集团 - 57、华夏票联(北京)科技有限公司 + - 58、拍拍贷 + - 59、北京尚德机构在线教育有限公司 - …… > 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。 @@ -181,6 +186,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 :xxl-job-executor-sample-spring:Spring版本,通过Spring容器管理执行器,比较通用,推荐这种方式; :xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器; :xxl-job-executor-sample-jfinal:JFinal版本,通过JFinal管理执行器; + :xxl-job-executor-sample-nutz:Nutz版本,通过Nutz管理执行器; ### 2.3 配置部署“调度中心” @@ -226,15 +232,17 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 至此“调度中心”项目已经部署成功。 #### 步骤三:调度中心集群(可选): -调度中心支持集群部署,提升调度系统可用性。 - -集群部署唯一要求为:保证每个集群节点配置(db和登陆账号等)保持一致。调度中心通过db配置区分不同集群。 +调度中心支持集群部署,提升调度系统容灾和可用性。 -调度中心在集群部署时可通过nginx负载均衡,此时可以为集群分配一个域名。该域名一方面可以用于访问,另一方面也可以用于配置执行器回调地址。 +调度中心集群部署时,几点要求和建议: +- DB配置保持一致; +- 登陆账号配置保持一致; +- 集群机器时钟保持一致(单机集群忽视); +- 建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。 ### 2.4 配置部署“执行器项目” - “执行器”项目:xxl-job-executor-sample-spring (如新建执行器项目,可参考该Sample示例执行器项目的配置步骤;) + “执行器”项目:xxl-job-executor-sample-spring (提供多种版本执行器供选择,现以Spring版本为例,可直接使用,也可以参考其并将现有项目改造成执行器) 作用:负责接收“调度中心”的调度并执行;可直接部署执行器,也可以将执行器集成到现有业务项目中。 #### 步骤一:maven依赖 @@ -278,15 +286,15 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 - + - + - + ``` @@ -316,7 +324,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ![输入图片说明](https://static.oschina.net/uploads/img/201704/27205910_o8HQ.png "在这里输入图片标题") -![输入图片说明](https://static.oschina.net/uploads/img/201704/27210202_SE2u.png "在这里输入图片标题") +![输入图片说明](https://static.oschina.net/uploads/img/201712/25183654_ZAsz.png "在这里输入图片标题") + #### 步骤二:“GLUE模式(Java)” 任务开发: 请点击任务右侧 “GLUE” 按钮,进入 “GLUE编辑器开发界面” ,见下图。“GLUE模式(Java)” 运行模式的任务默认已经初始化了示例任务代码,即打印Hello World。 @@ -365,14 +374,14 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "python" 脚本; GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 "nodejs" 脚本; - JobHandler:运行模式为 "BEAN模式" 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值; - - 子任务Key:每个任务都拥有一个唯一的任务Key(任务Key可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务Key所对应的任务的一次主动调度。 + - 子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。 - 阻塞处理策略:调度过于密集执行器来不及处理时的处理策略; 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行; 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败; 覆盖之前调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度任务; - 失败处理策略;调度失败时的处理策略; - 失败告警(默认):调度失败时,将会触发失败报警,如发送报警邮件; - 失败重试:调度失败时,将会主动进行一次失败重试调度,重试调度后仍然失败将会触发一失败告警。注意当任务以failover方式路由时,每次失败重试将会触发新一轮路由。 + 失败告警(默认):调度失败和执行失败时,都将会触发失败报警,默认会发送报警邮件; + 失败重试:调度失败时,除了进行失败告警之外,将会自动重试一次;注意在执行失败时不会重试,而是根据回调返回值判断是否重试; - 执行参数:任务执行所需的参数,多个参数时用逗号分隔,任务执行时将会把多个参数转换成数组传入; - 报警邮件:任务调度失败时邮件通知的邮箱地址,支持配置多邮箱地址,配置多个邮箱地址时用逗号分隔; - 负责人:任务的负责人; @@ -381,9 +390,11 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 任务逻辑以JobHandler的形式存在于“执行器”所在项目中,开发流程如下: #### 步骤一:执行器项目中,开发JobHandler: - - 1、 新建一个继承com.xxl.job.core.handler.IJobHandler的Java类; - - 2、 该类被Spring容器扫描为Bean实例,如加“@Component”注解; - - 3、 添加 “@JobHandler(value="自定义jobhandler名称")”注解,注解的value值为自定义的JobHandler名称,该名称对应的是调度中心新建任务的JobHandler属性的值。 + + - 1、继承"IJobHandler":“com.xxl.job.core.handler.IJobHandler”; + - 2、注册到Spring容器:添加“@Component”注解,被Spring容器扫描为Bean实例; + - 3、注册到执行器工厂:添加“@JobHandler(value="自定义jobhandler名称")”注解,注解value值对应的是调度中心新建任务的JobHandler属性的值。 + - 4、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志; (可参考Sample示例执行器中的DemoJobHandler,见下图) ![输入图片说明](https://static.oschina.net/uploads/img/201607/23232347_oLlM.png "在这里输入图片标题") @@ -391,7 +402,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 #### 步骤二:调度中心,新建调度任务 参考上文“配置属性详细说明”对新建的任务进行参数配置,运行模式选中 "BEAN模式",JobHandler属性填写任务注解“@JobHandler”中定义的值; -![输入图片说明](https://static.oschina.net/uploads/img/201704/27225124_yrcO.png "在这里输入图片标题") +![输入图片说明](https://static.oschina.net/uploads/img/201712/25183654_ZAsz.png "在这里输入图片标题") ### 3.2 GLUE模式(Java) 任务以源码方式维护在调度中心,支持通过Web IDE在线更新,实时编译和生效,因此不需要指定JobHandler。开发流程如下: @@ -399,7 +410,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 #### 步骤一:调度中心,新建调度任务: 参考上文“配置属性详细说明”对新建的任务进行参数配置,运行模式选中 "GLUE模式(Java)"; -![输入图片说明](https://static.oschina.net/uploads/img/201704/27210202_SE2u.png "在这里输入图片标题") +![输入图片说明](https://static.oschina.net/uploads/img/201712/25183837_tJOq.png "在这里输入图片标题") #### 步骤二:开发任务代码: 选中指定任务,点击该任务右侧“GLUE”按钮,将会前往GLUE任务的Web IDE界面,在该界面支持对任务代码进行开发(也可以在IDE中开发完成后,复制粘贴到编辑中)。 @@ -453,7 +464,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 2、"执行器列表" 中显示在线的执行器列表, 可通过"OnLine 机器"查看对应执行器的集群机器。 点击按钮 "+新增执行器" 弹框如下图, 可新增执行器配置: -![输入图片说明](https://static.oschina.net/uploads/img/201703/12223617_g3Im.png "在这里输入图片标题") + +![输入图片说明](https://static.oschina.net/uploads/img/201712/25183958_V3vF.png "在这里输入图片标题") ### 执行器属性说明 @@ -493,7 +505,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ![输入图片说明](https://static.oschina.net/uploads/img/201607/24133500_9235.png "在这里输入图片标题") -![输入图片说明](https://static.oschina.net/uploads/img/201704/27232850_inc8.png "在这里输入图片标题") +![输入图片说明](https://static.oschina.net/uploads/img/201712/25184206_UDSo.png "在这里输入图片标题") 调度时间:"调度中心"触发本次调度并向"执行器"发送任务执行信号的时间; 调度结果:"调度中心"触发本次调度的结果,200表示成功,500或其他表示失败; @@ -677,7 +689,6 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback 执行器如若集群部署,调度中心将会感知到在线的所有执行器,如“127.0.0.1:9997, 127.0.0.1:9998, 127.0.0.1:9999”。 当任务"路由策略"选择"故障转移(FAILOVER)"时,当调度中心每次发起调度请求时,会按照顺序对执行器发出心跳检测请求,第一个检测为存活状态的执行器将会被选定并发送调度请求。 -![输入图片说明](https://static.oschina.net/uploads/img/201705/11221144_P128.png "在这里输入图片标题") 调度成功后,可在日志监控界面查看“调度备注”,如下; ![输入图片说明](https://static.oschina.net/uploads/img/201703/12230733_jrdI.png "在这里输入图片标题") @@ -688,12 +699,10 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback #### 5.4.9 调度日志 调度中心每次进行任务调度,都会记录一条任务日志,任务日志主要包括以下三部分内容: -- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; +- 任务信息:包括“执行器地址”、“JobHandler”和“执行参数”等属性,点击任务ID按钮可查看,根据这些参数,可以精确的定位任务执行的具体机器和任务代码; - 调度信息:包括“调度时间”、“调度结果”和“调度日志”等,根据这些参数,可以了解“调度中心”发起调度请求时具体情况。 - 执行信息:包括“执行时间”、“执行结果”和“执行日志”等,根据这些参数,可以了解在“执行器”端任务执行的具体情况; -![输入图片说明](https://static.oschina.net/uploads/img/201703/12221436_c8Ru.png "在这里输入图片标题") - 调度日志,针对单次调度,属性说明如下: - 执行器地址:任务执行的机器地址; - JobHandler:Bean模式表示任务执行的JobHandler名称; @@ -707,9 +716,9 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback - 执行日志:任务执行过程中,业务代码中打印的完整执行日志,见“4.7 查看执行日志”; #### 5.4.10 任务依赖 -原理:XXL-JOB中每个任务都对应有一个任务Key,同时,每个任务支持设置属性“子任务Key”,因此,通过“任务Key”可以匹配任务依赖关系。 +原理:XXL-JOB中每个任务都对应有一个任务ID,同时,每个任务支持设置属性“子任务ID”,因此,通过“任务ID”可以匹配任务依赖关系。 -当父任务执行结束并且执行成功时,将会根据“子任务Key”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 +当父任务执行结束并且执行成功时,将会根据“子任务ID”匹配子任务依赖,如果匹配到子任务,将会主动触发一次子任务的执行。 在任务日志界面,点击任务的“执行备注”的“查看”按钮,可以看到匹配子任务以及触发子任务执行的日志信息,如无信息则表示未触发子任务执行,可参考下图。 @@ -738,9 +747,7 @@ xxl-job-admin#com.xxl.job.admin.controller.JobApiController.callback #### 5.5.4 执行器 -执行器实际上是一个内嵌的Jetty服务器,默认端口9999,如下图配置文件所示(参数:xxl.job.executor.port)。 - -![输入图片说明](https://static.oschina.net/uploads/img/201703/10174923_TgNO.png "在这里输入图片标题") +执行器实际上是一个内嵌的Jetty服务器,默认端口9999(配置项:xxl.job.executor.port)。 在项目启动时,执行器会通过“@JobHandler”识别Spring容器中“Bean模式任务”,以注解的value属性为key管理起来。 @@ -786,11 +793,21 @@ XXL-JOB会为每次调度请求生成一个单独的日志文件,需要通过 "分片广播" 以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。 -"分片广播" 和普通任务开发流程一致,不同之处在于可以可以获取分片参数,获取分片参数对象的代码如下(可参考Sample示例执行器中的示例任务"ShardingJobHandler" ): +"分片广播" 和普通任务开发流程一致,不同之处在于可以可以获取分片参数,获取分片参数进行分片业务处理。 - ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo(); +- Java语言任务获取分片参数方式:BEAN、GLUE模式(Java) +``` +// 可参考Sample示例执行器中的示例任务"ShardingJobHandler"了解试用 +ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo(); +``` +- 脚本语言任务获取分片参数方式:GLUE模式(Shell)、GLUE模式(Python)、GLUE模式(Nodejs) +``` +// 脚本任务入参固定为三个,依次为:任务传参、分片序号、分片总数。以Shell模式任务为例,获取分片参数代码如下 +echo "分片序号 index = $2" +echo "分片总数 total = $3" +``` -该分片参数对象拥有两个属性: +分片参数属性说明: index:当前分片序号(从0开始),执行器集群列表中当前执行器的序号; total:总分片数,执行器集群的总机器数量; @@ -819,7 +836,7 @@ XXL-JOB会为每次调度请求生成一个单独的日志文件,需要通过 调度中心API服务位置:com.xxl.job.core.biz.AdminBiz.java -调度中心API服务请求参考代码:com.xxl.job.dao.impl.AdminBizTest.java +调度中心API服务请求参考代码:com.xxl.job.adminbiz.AdminBizTest.java ### 5.12 执行器API服务 执行器提供了API服务,供调度中心选择使用,目前提供的API服务有: @@ -834,6 +851,15 @@ XXL-JOB会为每次调度请求生成一个单独的日志文件,需要通过 执行器API服务请求参考代码:com.xxl.executor.test.DemoJobHandlerTest +### 5.13 故障转移 & 失败重试 +一次完整任务流程包括"调度(调度中心) + 执行(执行器)"两个阶段。 + +- "故障转移"发生在调度阶段,在执行器集群部署时,如果某一台执行器发生故障,该策略支持自动进行Failover切换到一台正常的执行器机器并且完成调度请求流程。 +- "失败重试"发生在"调度 + 执行"两个阶段,如下: + - 调度中心调度失败时,任务失败处理策略选择"失败重试",将会自动重试一次; + - 执行器运行失败时,任务执行结果返回"失败重试(IJobHandler.FAIL_RETRY)"回调,将会自动重试一次; + + ## 六、版本更新日志 ### 6.1 版本 V1.1.x,新特性[2015-12-05] **【于V1.1.x版本,XXL-JOB正式应用于我司,内部定制别名为 “Ferrari”,新接入应用推荐使用最新版本】** @@ -1049,40 +1075,51 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段 - 10、任务日志文件路径时间戳格式化时SimpleDateFormat并发问题解决; ### 6.20 版本 V1.9.0 特性[迭代中] -- 1、新增任务运行模式 "GLUE模式(NodeJS) ",支持NodeJS脚本任务; -- 2、失败告警策略扩展:默认提供邮件失败告警,可扩展短信等,扩展代码位置为 "JobFailMonitorHelper.failAlarm"; -- 3、修复任务监控线程被耗时任务阻塞的问题; -- 4、修复任务监控线程无法监控任务触发和执行状态均未0的问题; -- 5、调度中心项目日志配置改为xml文件格式; -- 6、执行器动态代理对象,拦截非业务方法的执行; -- 7、底层系统日志级别规范调整,清理遗留代码; -- 8、修改JobThread捕获Error错误不更新JobLog的问题; -- 9、任务注解调整为 “@JobHandler”,与任务注解统一; -- 10、执行器端口支持随机生成(小于等于0时),避免端口定义冲突; -- 11、任务Cron长度扩展支持至128位; -- 12、调度报表优化,支持时间区间筛选; +- 1、新增Nutz执行器Sample示例项目; +- 2、新增任务运行模式 "GLUE模式(NodeJS) ",支持NodeJS脚本任务; +- 3、脚本任务Shell、Python和Nodejs等支持获取分片参数; +- 4、失败重试,完整支持:调度中心调度失败且启用"失败重试"策略时,将会自动重试一次;执行器执行失败且回调失败重试状态(新增失败重试状态返回值)时,也将会自动重试一次; +- 5、失败告警策略扩展:默认提供邮件失败告警,可扩展短信等,扩展代码位置为 "JobFailMonitorHelper.failAlarm"; +- 6、执行器端口支持自动生成(小于等于0时),避免端口定义冲突; +- 7、调度报表优化,支持时间区间筛选; +- 8、Log组件支持输出异常栈信息,底层实现优化; +- 9、告警邮件样式优化,调整为表格形式,邮件组件调整为commons-email简化邮件操作; +- 10、项目依赖升级,如spring、jackson等; +- 11、任务日志,记录发起调度的机器信息; +- 12、交互优化,如登陆注销; +- 13、任务Cron长度扩展支持至128位,支持负责类型Cron设置; +- 14、执行器地址录入交互优化,地址长度扩展支持至512位,支持大规模执行器集群配置; +- 15、任务参数“IJobHandler.execute”入参改为“String params”,增强入参通用性。 +- 16、JobHandler提供init/destroy方法,支持在JobHandler初始化和销毁时进行附加操作; +- 17、任务注解调整为 “@JobHandler”,与任务抽象接口统一; +- 18、修复任务监控线程被耗时任务阻塞的问题; +- 19、修复任务监控线程无法监控任务触发和执行状态均未0的问题; +- 20、执行器动态代理对象,拦截非业务方法的执行; +- 21、修复JobThread捕获Error错误不更新JobLog的问题; +- 22、修复任务列表界面左侧菜单合并时样式错乱问题; +- 23、调度中心项目日志配置改为xml文件格式; +- 24、Log地址格式兼容,支持非"/"结尾路径配置; +- 25、底层系统日志级别规范调整,清理遗留代码; +- 26、建表SQL优化,支持同步创建制定编码的库和表; +- 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly; +- 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 +- 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; - 2、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动;目前采用IP自然排序,可以满足需求,待定; -- 3、失败重试完整支持:任务流程分为触发和执行,目前仅支持触发失败的重试;后续支持任务执行失败的重试,通过任务返回值判断。 +- 3、任务单机多线程:提升任务单机并行处理能力; - 4、回调失败丢包问题:执行器回调失败写文件,重启或周期性回调重试;调度中心周期性请求并同步未回调的执行结果; - 5、任务依赖,流程图,子任务+会签任务,各节点日志; - 6、调度任务优先级; - 7、移除quartz依赖,重写调度模块:新增或恢复任务时将下次执行记录插入delayqueue,调度中心集群竞争分布式锁,成功节点批量加载到期delayqueue数据,批量执行。 - 8、springboot 和 docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用; - 9、国际化:调度中心界面。 -- 10、任务类方法"IJobHandler.execute"的参数类型改为"string",进一步方便参数传递;任务注解和任务类统一并改为"JobHandler""; -- 11、任务日志,记录发起调度的机器信息; -- 12、任务告警逻辑调整:任务调度,以及任务回调失败时,均推送监控队列。后期考虑通过任务Log字段控制告警状态; -- 13、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; -- 14、脚本任务 Shell、Python和Nodejs,如何友好获取分片参数; -- 15、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; -- 16、任务告警邮件优化,调整为表格形式; -- 17、JobHandler提供 init/destroy 方法,支持自定义任务线程销毁逻辑; -- 18、cron表达式的最大长度调整,兼容复杂类型cron; -- 19、执行器回调地址/日志地址格式兼容,是否已"/"结尾均支持; -- 20、任务单机多线程:提升任务单机并行处理能力; +- 10、任务告警逻辑调整:任务调度,以及任务回调失败时,均推送监控队列。后期考虑通过任务Log字段控制告警状态; +- 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件; +- 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性; +- 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发; +- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题; ## 七、其他 diff --git a/doc/db/tables_xxl_job.sql b/doc/db/tables_xxl_job.sql index 87bb23be..ed328959 100644 --- a/doc/db/tables_xxl_job.sql +++ b/doc/db/tables_xxl_job.sql @@ -1,6 +1,8 @@ CREATE database if NOT EXISTS `xxl-job` default character set utf8 collate utf8_general_ci; use `xxl-job`; + + CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( SCHED_NAME VARCHAR(120) NOT NULL, @@ -158,14 +160,14 @@ CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_INFO` ( `alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件', `executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略', `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler', - `executor_param` varchar(255) DEFAULT NULL COMMENT '执行器任务参数', + `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数', `executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略', `executor_fail_strategy` varchar(50) DEFAULT NULL COMMENT '失败处理策略', `glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型', `glue_source` text COMMENT 'GLUE源代码', `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注', `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间', - `child_jobkey` varchar(255) DEFAULT NULL COMMENT '子任务Key', + `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -176,7 +178,7 @@ CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_LOG` ( `glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE类型', `executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址', `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler', - `executor_param` varchar(255) DEFAULT NULL COMMENT 'executor_param', + `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数', `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', `trigger_code` varchar(255) NOT NULL DEFAULT '0' COMMENT '调度-结果', `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', @@ -212,7 +214,7 @@ CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_GROUP` ( `title` varchar(12) NOT NULL COMMENT '执行器名称', `order` tinyint(4) NOT NULL DEFAULT '0' COMMENT '排序', `address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型:0=自动注册、1=手动录入', - `address_list` varchar(200) DEFAULT NULL COMMENT '执行器地址列表,多地址逗号分隔', + `address_list` varchar(512) DEFAULT NULL COMMENT '执行器地址列表,多地址逗号分隔', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/pom.xml b/pom.xml index d2f31344..f7f3d33c 100644 --- a/pom.xml +++ b/pom.xml @@ -20,31 +20,31 @@ 3.0.1 2.2 - 3.2.18.RELEASE - 1.9.13 - 1.8.7 + 4.3.13.RELEASE + 2.9.3 + 1.8.13 1.7.25 - 2.3.20 - 4.11 + 2.3.23 + 4.12 9.2.22.v20170606 - 4.0.38 - 4.3.6 - + 4.0.51 + 4.5.4 + 1.3 - 1.9.2 - 2.6 + 4.1 + 3.7 + 1.5 0.9.5.2 - 5.1.29 - 1.2.2 - 3.2.8 + 5.1.45 + 1.3.1 + 3.4.5 - 2.4.5 - 1.4.6 + 2.4.13 2.3.0 - 1.5.6.RELEASE + 1.5.9.RELEASE diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index b86c7ebf..2498c234 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -40,18 +40,22 @@ - org.codehaus.jackson - jackson-mapper-asl - ${jackson-mapper-asl.version} + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} - + - org.slf4j - slf4j-log4j12 - ${slf4j-api.version} + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + + + javax.servlet.jsp + jsp-api + ${jsp-api.version} - org.freemarker @@ -59,37 +63,37 @@ ${freemarker.version} - + - commons-beanutils - commons-beanutils - ${commons-beanutils.version} + org.slf4j + slf4j-log4j12 + ${slf4j-api.version} - + - commons-lang - commons-lang - ${commons-lang.version} + junit + junit + ${junit.version} + test - + - javax.servlet - javax.servlet-api - ${javax.servlet-api.version} + org.apache.commons + commons-collections4 + ${commons-collections4.version} + - javax.servlet.jsp - jsp-api - ${jsp-api.version} + org.apache.commons + commons-lang3 + ${commons-lang3.version} - - + - junit - junit - ${junit.version} - test + org.apache.commons + commons-email + ${commons-email.version} @@ -116,7 +120,6 @@ ${mybatis.version} - org.apache.httpcomponents @@ -124,13 +127,6 @@ ${httpclient.version} - - - javax.mail - mail - ${mail.version} - - org.quartz-scheduler diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java index cc3c6120..f4b1cadd 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java @@ -2,10 +2,9 @@ package com.xxl.job.admin.controller; import com.xxl.job.admin.controller.annotation.PermessionLimit; import com.xxl.job.admin.controller.interceptor.PermissionInterceptor; -import com.xxl.job.admin.core.util.PropertiesUtil; import com.xxl.job.admin.service.XxlJobService; import com.xxl.job.core.biz.model.ReturnT; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -61,18 +60,21 @@ public class IndexController { @ResponseBody @PermessionLimit(limit=false) public ReturnT loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){ - if (!PermissionInterceptor.ifLogin(request)) { - if (StringUtils.isNotBlank(userName) && StringUtils.isNotBlank(password) - && PropertiesUtil.getString("xxl.job.login.username").equals(userName) - && PropertiesUtil.getString("xxl.job.login.password").equals(password)) { - boolean ifRem = false; - if (StringUtils.isNotBlank(ifRemember) && "on".equals(ifRemember)) { - ifRem = true; - } - PermissionInterceptor.login(response, ifRem); - } else { - return new ReturnT(500, "账号或密码错误"); - } + // valid + if (PermissionInterceptor.ifLogin(request)) { + return ReturnT.SUCCESS; + } + + // param + if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)){ + return new ReturnT(500, "账号或密码为空"); + } + boolean ifRem = (StringUtils.isNotBlank(ifRemember) && "on".equals(ifRemember))?true:false; + + // do login + boolean loginRet = PermissionInterceptor.login(response, userName, password, ifRem); + if (!loginRet) { + return new ReturnT(500, "账号或密码错误"); } return ReturnT.SUCCESS; } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java index 496d34e7..6211f3c7 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java @@ -4,7 +4,7 @@ import com.xxl.job.admin.core.model.XxlJobGroup; import com.xxl.job.admin.dao.XxlJobGroupDao; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.core.biz.model.ReturnT; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java index f3192737..a31536cf 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java @@ -11,8 +11,8 @@ import com.xxl.job.core.biz.ExecutorBiz; import com.xxl.job.core.biz.model.LogResult; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.rpc.netcom.NetComClientProxy; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.time.DateUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java index 8072b458..bd84534f 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java @@ -1,17 +1,17 @@ package com.xxl.job.admin.controller.interceptor; -import java.util.HashMap; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.ArrayUtils; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; +import java.util.HashMap; /** * push cookies to model as cookieMap + * * @author xuxueli 2015-12-12 18:09:04 */ public class CookieInterceptor extends HandlerInterceptorAdapter { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java index ab565e1f..1d6facf5 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java @@ -3,6 +3,7 @@ package com.xxl.job.admin.controller.interceptor; import com.xxl.job.admin.controller.annotation.PermessionLimit; import com.xxl.job.admin.core.util.CookieUtil; import com.xxl.job.admin.core.util.PropertiesUtil; +import org.apache.commons.codec.digest.DigestUtils; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @@ -12,20 +13,38 @@ import java.math.BigInteger; /** * 权限拦截, 简易版 + * * @author xuxueli 2015-12-12 18:09:04 */ public class PermissionInterceptor extends HandlerInterceptorAdapter { - - public static final String LOGIN_IDENTITY_KEY = "LOGIN_IDENTITY"; + + + public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY"; public static final String LOGIN_IDENTITY_TOKEN; static { String username = PropertiesUtil.getString("xxl.job.login.username"); String password = PropertiesUtil.getString("xxl.job.login.password"); - String temp = username + "_" + password; - LOGIN_IDENTITY_TOKEN = new BigInteger(1, temp.getBytes()).toString(16); + + // login token + String tokenTmp = DigestUtils.md5Hex(username + "_" + password); + tokenTmp = new BigInteger(1, tokenTmp.getBytes()).toString(16); + + LOGIN_IDENTITY_TOKEN = tokenTmp; } - - public static boolean login(HttpServletResponse response, boolean ifRemember){ + + + + public static boolean login(HttpServletResponse response, String username, String password, boolean ifRemember){ + + // login token + String tokenTmp = DigestUtils.md5Hex(username + "_" + password); + tokenTmp = new BigInteger(1, tokenTmp.getBytes()).toString(16); + + if (!LOGIN_IDENTITY_TOKEN.equals(tokenTmp)){ + return false; + } + + // do login CookieUtil.set(response, LOGIN_IDENTITY_KEY, LOGIN_IDENTITY_TOKEN, ifRemember); return true; } @@ -40,6 +59,8 @@ public class PermissionInterceptor extends HandlerInterceptorAdapter { return true; } + + @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java index 85fb4a10..040c9226 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java @@ -1,6 +1,6 @@ package com.xxl.job.admin.core.model; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.Arrays; diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java index ec1138d6..51847ac1 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java @@ -31,7 +31,7 @@ public class XxlJobInfo { private String glueRemark; // GLUE备注 private Date glueUpdatetime; // GLUE更新时间 - private String childJobKey; // 子任务Key + private String childJobId; // 子任务ID,多个逗号分隔 // copy from quartz private String jobStatus; // 任务状态 【base on quartz】 @@ -172,12 +172,12 @@ public class XxlJobInfo { this.glueUpdatetime = glueUpdatetime; } - public String getChildJobKey() { - return childJobKey; + public String getChildJobId() { + return childJobId; } - public void setChildJobKey(String childJobKey) { - this.childJobKey = childJobKey; + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; } public String getJobStatus() { diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java index a19c1781..c9f7f04d 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -6,7 +6,8 @@ import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.core.biz.model.ReturnT; -import org.apache.commons.collections.CollectionUtils; +import com.xxl.job.core.handler.IJobHandler; +import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,6 +28,8 @@ public class JobFailMonitorHelper { return instance; } + // ---------------------- monitor ---------------------- + private LinkedBlockingQueue queue = new LinkedBlockingQueue(0xfff8); private Thread monitorThread; @@ -51,13 +54,15 @@ public class JobFailMonitorHelper { if (log == null) { continue; } - if (ReturnT.SUCCESS_CODE == log.getTriggerCode() && log.getHandleCode() == 0) { + if (IJobHandler.SUCCESS.getCode() == log.getTriggerCode() && log.getHandleCode() == 0) { JobFailMonitorHelper.monitor(jobLogId); logger.info(">>>>>>>>>>> job monitor, job running, JobLogId:{}", jobLogId); - } else if (ReturnT.SUCCESS_CODE == log.getTriggerCode() && ReturnT.SUCCESS_CODE == log.getHandleCode()) { + } else if (IJobHandler.SUCCESS.getCode() == log.getHandleCode()) { // job success, pass logger.info(">>>>>>>>>>> job monitor, job success, JobLogId:{}", jobLogId); - } else if (ReturnT.FAIL_CODE == log.getTriggerCode() || ReturnT.FAIL_CODE == log.getHandleCode()) { + } else if (IJobHandler.FAIL.getCode() == log.getTriggerCode() + || IJobHandler.FAIL.getCode() == log.getHandleCode() + || IJobHandler.FAIL_RETRY.getCode() == log.getHandleCode() ) { // job fail, failAlarm(log); logger.info(">>>>>>>>>>> job monitor, job fail, JobLogId:{}", jobLogId); @@ -94,6 +99,46 @@ public class JobFailMonitorHelper { monitorThread.start(); } + public void toStop(){ + toStop = true; + // interrupt and wait + monitorThread.interrupt(); + try { + monitorThread.join(); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + + // producer + public static void monitor(int jobLogId){ + getInstance().queue.offer(jobLogId); + } + + + // ---------------------- alarm ---------------------- + + // email alarm template + private static final String mailBodyTemplate = "
监控告警明细:" + + "\n" + + " " + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
执行器任务ID任务描述告警类型
{0}{1}{2}调度失败
"; + /** * fail alarm * @@ -107,10 +152,12 @@ public class JobFailMonitorHelper { Set emailSet = new HashSet(Arrays.asList(info.getAlarmEmail().split(","))); for (String email: emailSet) { - String title = "《调度监控报警》(任务调度中心XXL-JOB)"; XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); - String content = MessageFormat.format("任务调度失败, 执行器名称:{0}, 任务描述:{1}.", group!=null?group.getTitle():"null", info.getJobDesc()); - MailUtil.sendMail(email, title, content, false, null); + + String title = "调度中心监控报警"; + String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); + + MailUtil.sendMail(email, title, content); } } @@ -118,20 +165,4 @@ public class JobFailMonitorHelper { } - public void toStop(){ - toStop = true; - // interrupt and wait - monitorThread.interrupt(); - try { - monitorThread.join(); - } catch (InterruptedException e) { - logger.error(e.getMessage(), e); - } - } - - // producer - public static void monitor(int jobLogId){ - getInstance().queue.offer(jobLogId); - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryMonitorHelper.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryMonitorHelper.java index 94f40a0e..647c02ed 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryMonitorHelper.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryMonitorHelper.java @@ -4,8 +4,8 @@ import com.xxl.job.admin.core.model.XxlJobGroup; import com.xxl.job.admin.core.model.XxlJobRegistry; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; import com.xxl.job.core.enums.RegistryConfig; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java index 6482922f..bf3c8567 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java @@ -11,7 +11,8 @@ import com.xxl.job.core.biz.ExecutorBiz; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; -import org.apache.commons.collections.CollectionUtils; +import com.xxl.job.core.util.IpUtil; +import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,11 +67,12 @@ public class XxlJobTrigger { ReturnT triggerResult = new ReturnT(null); StringBuffer triggerMsgSb = new StringBuffer(); - triggerMsgSb.append("注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" ); + triggerMsgSb.append("调度机器:").append(IpUtil.getIp()); + triggerMsgSb.append("
执行器-注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" ); + triggerMsgSb.append("
执行器-地址列表:").append(group.getRegistryList()); + triggerMsgSb.append("
路由策略:").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01 triggerMsgSb.append("
阻塞处理策略:").append(blockStrategy.getTitle()); triggerMsgSb.append("
失败处理策略:").append(failStrategy.getTitle()); - triggerMsgSb.append("
地址列表:").append(group.getRegistryList()); - triggerMsgSb.append("
路由策略:").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01 // 3、trigger-valid if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) { @@ -115,72 +117,73 @@ public class XxlJobTrigger { logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId()); } - return; - } - - // 1、save log-id - XxlJobLog jobLog = new XxlJobLog(); - jobLog.setJobGroup(jobInfo.getJobGroup()); - jobLog.setJobId(jobInfo.getId()); - XxlJobDynamicScheduler.xxlJobLogDao.save(jobLog); - logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId()); - - // 2、prepare trigger-info - //jobLog.setExecutorAddress(executorAddress); - jobLog.setGlueType(jobInfo.getGlueType()); - jobLog.setExecutorHandler(jobInfo.getExecutorHandler()); - jobLog.setExecutorParam(jobInfo.getExecutorParam()); - jobLog.setTriggerTime(new Date()); - - ReturnT triggerResult = new ReturnT(null); - StringBuffer triggerMsgSb = new StringBuffer(); - triggerMsgSb.append("注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" ); - triggerMsgSb.append("
阻塞处理策略:").append(blockStrategy.getTitle()); - triggerMsgSb.append("
失败处理策略:").append(failStrategy.getTitle()); - triggerMsgSb.append("
地址列表:").append(group.getRegistryList()); - triggerMsgSb.append("
路由策略:").append(executorRouteStrategyEnum.getTitle()); - - // 3、trigger-valid - if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) { - triggerResult.setCode(ReturnT.FAIL_CODE); - triggerMsgSb.append("
----------------------
").append("调度失败:").append("执行器地址为空"); - } + } else { + // 1、save log-id + XxlJobLog jobLog = new XxlJobLog(); + jobLog.setJobGroup(jobInfo.getJobGroup()); + jobLog.setJobId(jobInfo.getId()); + XxlJobDynamicScheduler.xxlJobLogDao.save(jobLog); + logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId()); + + // 2、prepare trigger-info + //jobLog.setExecutorAddress(executorAddress); + jobLog.setGlueType(jobInfo.getGlueType()); + jobLog.setExecutorHandler(jobInfo.getExecutorHandler()); + jobLog.setExecutorParam(jobInfo.getExecutorParam()); + jobLog.setTriggerTime(new Date()); + + ReturnT triggerResult = new ReturnT(null); + StringBuffer triggerMsgSb = new StringBuffer(); + triggerMsgSb.append("调度机器:").append(IpUtil.getIp()); + triggerMsgSb.append("
执行器-注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" ); + triggerMsgSb.append("
执行器-地址列表:").append(group.getRegistryList()); + triggerMsgSb.append("
路由策略:").append(executorRouteStrategyEnum.getTitle()); + triggerMsgSb.append("
阻塞处理策略:").append(blockStrategy.getTitle()); + triggerMsgSb.append("
失败处理策略:").append(failStrategy.getTitle()); + + // 3、trigger-valid + if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) { + triggerResult.setCode(ReturnT.FAIL_CODE); + triggerMsgSb.append("
----------------------
").append("调度失败:").append("执行器地址为空"); + } - if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) { - // 4.1、trigger-param - TriggerParam triggerParam = new TriggerParam(); - triggerParam.setJobId(jobInfo.getId()); - triggerParam.setExecutorHandler(jobInfo.getExecutorHandler()); - triggerParam.setExecutorParams(jobInfo.getExecutorParam()); - triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); - triggerParam.setLogId(jobLog.getId()); - triggerParam.setLogDateTim(jobLog.getTriggerTime().getTime()); - triggerParam.setGlueType(jobInfo.getGlueType()); - triggerParam.setGlueSource(jobInfo.getGlueSource()); - triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime()); - triggerParam.setBroadcastIndex(0); - triggerParam.setBroadcastTotal(1); - - // 4.2、trigger-run (route run / trigger remote executor) - triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList); - triggerMsgSb.append("

>>>>>>>>>>>触发调度<<<<<<<<<<<
").append(triggerResult.getMsg()); - - // 4.3、trigger (fail retry) - if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) { + if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) { + // 4.1、trigger-param + TriggerParam triggerParam = new TriggerParam(); + triggerParam.setJobId(jobInfo.getId()); + triggerParam.setExecutorHandler(jobInfo.getExecutorHandler()); + triggerParam.setExecutorParams(jobInfo.getExecutorParam()); + triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); + triggerParam.setLogId(jobLog.getId()); + triggerParam.setLogDateTim(jobLog.getTriggerTime().getTime()); + triggerParam.setGlueType(jobInfo.getGlueType()); + triggerParam.setGlueSource(jobInfo.getGlueSource()); + triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime()); + triggerParam.setBroadcastIndex(0); + triggerParam.setBroadcastTotal(1); + + // 4.2、trigger-run (route run / trigger remote executor) triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList); - triggerMsgSb.append("

>>>>>>>>>>>失败重试<<<<<<<<<<<
").append(triggerResult.getMsg()); + triggerMsgSb.append("

>>>>>>>>>>>触发调度<<<<<<<<<<<
").append(triggerResult.getMsg()); + + // 4.3、trigger (fail retry) + if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) { + triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList); + triggerMsgSb.append("

>>>>>>>>>>>调度失败重试<<<<<<<<<<<
").append(triggerResult.getMsg()); + } } - } - // 5、save trigger-info - jobLog.setExecutorAddress(triggerResult.getContent()); - jobLog.setTriggerCode(triggerResult.getCode()); - jobLog.setTriggerMsg(triggerMsgSb.toString()); - XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog); + // 5、save trigger-info + jobLog.setExecutorAddress(triggerResult.getContent()); + jobLog.setTriggerCode(triggerResult.getCode()); + jobLog.setTriggerMsg(triggerMsgSb.toString()); + XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog); + + // 6、monitor triger + JobFailMonitorHelper.monitor(jobLog.getId()); + logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId()); + } - // 6、monitor triger - JobFailMonitorHelper.monitor(jobLog.getId()); - logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId()); } /** @@ -195,7 +198,7 @@ public class XxlJobTrigger { ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address); runResult = executorBiz.run(triggerParam); } catch (Exception e) { - logger.error(e.getMessage(), e); + logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e); runResult = new ReturnT(ReturnT.FAIL_CODE, ""+e ); } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java index 19a6751f..31f30ee3 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java @@ -6,9 +6,11 @@ import javax.servlet.http.HttpServletResponse; /** * Cookie.Util + * * @author xuxueli 2015-12-12 18:01:06 */ public class CookieUtil { + // 默认缓存时间,单位/秒, 2H private static final int COOKIE_MAX_AGE = 60 * 60 * 2; // 保存路径,根路径 @@ -16,43 +18,39 @@ public class CookieUtil { /** * 保存 + * * @param response * @param key * @param value * @param ifRemember */ public static void set(HttpServletResponse response, String key, String value, boolean ifRemember) { - - int age = COOKIE_MAX_AGE; - if (ifRemember) { - age = COOKIE_MAX_AGE; - } else { - age = -1; - } - - Cookie cookie = new Cookie(key, value); - cookie.setMaxAge(age); // Cookie过期时间,单位/秒 - cookie.setPath(COOKIE_PATH); // Cookie适用的路径 - response.addCookie(cookie); + int age = ifRemember?COOKIE_MAX_AGE:-1; + set(response, key, value, null, COOKIE_PATH, age, true); } /** * 保存 + * * @param response * @param key * @param value * @param maxAge */ - private static void set(HttpServletResponse response, - String key, String value, int maxAge, String path) { + private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) { Cookie cookie = new Cookie(key, value); - cookie.setMaxAge(maxAge); // Cookie过期时间,单位/秒 - cookie.setPath(path); // Cookie适用的路径 + if (domain != null) { + cookie.setDomain(domain); + } + cookie.setPath(path); + cookie.setMaxAge(maxAge); + cookie.setHttpOnly(isHttpOnly); response.addCookie(cookie); } /** * 查询value + * * @param request * @param key * @return @@ -67,6 +65,7 @@ public class CookieUtil { /** * 查询Cookie + * * @param request * @param key */ @@ -84,15 +83,15 @@ public class CookieUtil { /** * 删除Cookie + * * @param request * @param response * @param key - * @param domainName */ public static void remove(HttpServletRequest request, HttpServletResponse response, String key) { Cookie cookie = get(request, key); if (cookie != null) { - set(response, key, "", 0, COOKIE_PATH); + set(response, key, "", null, COOKIE_PATH, 0, true); } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/MailUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/MailUtil.java index c37a9295..e000b157 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/MailUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/MailUtil.java @@ -1,21 +1,16 @@ package com.xxl.job.admin.core.util; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.mail.DefaultAuthenticator; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.HtmlEmail; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.mail.javamail.JavaMailSenderImpl; -import org.springframework.mail.javamail.MimeMessageHelper; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeUtility; -import java.io.File; -import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.nio.charset.Charset; /** * 邮件发送.Util + * * @author xuxueli 2016-3-12 15:06:20 */ public class MailUtil { @@ -33,154 +28,44 @@ public class MailUtil { password = PropertiesUtil.getString("xxl.job.mail.password"); sendNick = PropertiesUtil.getString("xxl.job.mail.sendNick"); } - - /** - - - - - - - - - true - true - - - - - */ + /** - * 发送邮件 (完整版)(结合Spring) - * - * //@param javaMailSender: 发送Bean - * //@param sendFrom : 发送人邮箱 - * //@param sendNick : 发送人昵称 - * @param toAddress : 收件人邮箱 - * @param mailSubject : 邮件主题 - * @param mailBody : 邮件正文 - * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 - * @param attachments : 附件 + * + * @param toAddress 收件人邮箱 + * @param mailSubject 邮件主题 + * @param mailBody 邮件正文 + * @return */ - @SuppressWarnings("null") - public static boolean sendMailSpring(String toAddress, String mailSubject, String mailBody, boolean mailBodyIsHtml,File[] attachments) { - JavaMailSender javaMailSender = null;//ResourceBundle.getInstance().getJavaMailSender(); + public static boolean sendMail(String toAddress, String mailSubject, String mailBody){ + try { - MimeMessage mimeMessage = javaMailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); // 设置utf-8或GBK编码,否则邮件会有乱码;multipart,true表示文件上传 + // Create the email message + HtmlEmail email = new HtmlEmail(); + //email.setDebug(true); // 将会打印一些log + //email.setTLS(true); // 是否TLS校验,,某些邮箱需要TLS安全校验,同理有SSL校验 + //email.setSSL(true); - helper.setFrom(username, sendNick); - helper.setTo(toAddress); + email.setHostName(host); + email.setSmtpPort(Integer.valueOf(port)); + //email.setSslSmtpPort(port); + email.setAuthenticator(new DefaultAuthenticator(username, password)); + email.setCharset(Charset.defaultCharset().name()); - // 设置收件人抄送的名片和地址(相当于群发了) - //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>")); + email.setFrom(username, sendNick); + email.addTo(toAddress); + email.setSubject(mailSubject); + email.setMsg(mailBody); - helper.setSubject(mailSubject); - helper.setText(mailBody, mailBodyIsHtml); - - // 添加附件 - if (ArrayUtils.isNotEmpty(attachments)) { - for (File file : attachments) { - helper.addAttachment(MimeUtility.encodeText(file.getName()), file); - } - } - - // 群发 - //MimeMessage[] mailMessages = { mimeMessage }; - - javaMailSender.send(mimeMessage); - return true; - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - return false; - } - - /** - * 发送邮件 (完整版) (纯JavaMail) - * - * @param toAddress : 收件人邮箱 - * @param mailSubject : 邮件主题 - * @param mailBody : 邮件正文 - * @param mailBodyIsHtml: 邮件正文格式,true:HTML格式;false:文本格式 - * //@param inLineFile : 内嵌文件 - * @param attachments : 附件 - */ - public static boolean sendMail (String toAddress, String mailSubject, String mailBody, - boolean mailBodyIsHtml, File[] attachments){ - try { - // 创建邮件发送类 JavaMailSender (用于发送多元化邮件,包括附件,图片,html 等) - JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); - mailSender.setHost(host); // 设置邮件服务主机 - mailSender.setUsername(username); // 发送者邮箱的用户名 - mailSender.setPassword(password); // 发送者邮箱的密码 - - // 配置文件,用于实例化java.mail.session - Properties pro = new Properties(); - pro.put("mail.transport.protocol", "smtp"); - pro.put("mail.smtp.auth", "true"); // 登录SMTP服务器,需要获得授权 (网易163邮箱新近注册的邮箱均不能授权,测试 sohu 的邮箱可以获得授权) - pro.put("mail.smtp.socketFactory.port", port); - pro.put("mail.smtp.socketFactory.fallback", "false"); - mailSender.setJavaMailProperties(pro); - - // 创建多元化邮件 (创建 mimeMessage 帮助类,用于封装信息至 mimeMessage) - MimeMessage mimeMessage = mailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, ArrayUtils.isNotEmpty(attachments), "UTF-8"); - - helper.setFrom(username, sendNick); - helper.setTo(toAddress); - - helper.setSubject(mailSubject); - helper.setText(mailBody, mailBodyIsHtml); - - // 设置收件人抄送的名片和地址(相当于群发) - //helper.setCc(InternetAddress.parse(MimeUtility.encodeText("邮箱001") + " <@163.com>," + MimeUtility.encodeText("邮箱002") + " <@foxmail.com>")); + //email.attach(attachment); // add the attachment - // 内嵌文件,第1个参数为cid标识这个文件,第2个参数为资源 - //helper.addInline(MimeUtility.encodeText(inLineFile.getName()), inLineFile); - - // 添加附件 - /*if (ArrayUtils.isNotEmpty(attachments)) { - for (File file : attachments) { - helper.addAttachment(MimeUtility.encodeText(file.getName()), file); - } - }*/ - - // 群发 - //MimeMessage[] mailMessages = { mimeMessage }; - - mailSender.send(mimeMessage); + email.send(); // send the email return true; - } catch (Exception e) { + } catch (EmailException e) { logger.error(e.getMessage(), e); + } return false; } - - static int total = 0; - public static void main(String[] args) { - - ExecutorService exec = Executors.newCachedThreadPool(); - for (int i = 0; i < 1; i++) { - exec.execute(new Thread(new Runnable() { - @Override - public void run() { - while(total < 1){ - String mailBody = "

新书快递通知

你的新书快递申请已推送新书,请到空间" - + "中查看"; - - sendMail("931591021@qq.com", "测试邮件", mailBody, true, null); - System.out.println(total); - total++; - } - } - })); - } - } - + } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/PropertiesUtil.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/PropertiesUtil.java index ed80e708..a3c60077 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/PropertiesUtil.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/PropertiesUtil.java @@ -12,6 +12,7 @@ import java.util.Properties; /** * properties util + * * @author xuxueli 2015-8-28 10:35:53 */ public class PropertiesUtil { @@ -33,9 +34,5 @@ public class PropertiesUtil { } return null; } - - public static void main(String[] args) { - System.out.println(getString("xxl.job.login.username")); - } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java index 718b4554..352b4c95 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java @@ -1,10 +1,7 @@ package com.xxl.job.admin.service.impl; -import com.xxl.job.admin.controller.JobApiController; import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobLog; -import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; -import com.xxl.job.admin.core.trigger.XxlJobTrigger; import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobRegistryDao; @@ -13,8 +10,8 @@ import com.xxl.job.core.biz.AdminBiz; import com.xxl.job.core.biz.model.HandleCallbackParam; import com.xxl.job.core.biz.model.RegistryParam; import com.xxl.job.core.biz.model.ReturnT; -import org.apache.commons.lang.StringUtils; -import org.quartz.SchedulerException; +import com.xxl.job.core.handler.IJobHandler; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -46,7 +43,7 @@ public class AdminBizImpl implements AdminBiz { for (HandleCallbackParam handleCallbackParam: callbackParamList) { ReturnT callbackResult = callback(handleCallbackParam); logger.info(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}", - (callbackResult.getCode()==ReturnT.SUCCESS_CODE?"success":"fail"), handleCallbackParam, callbackResult); + (callbackResult.getCode()==IJobHandler.SUCCESS.getCode()?"success":"fail"), handleCallbackParam, callbackResult); } return ReturnT.SUCCESS; @@ -58,28 +55,39 @@ public class AdminBizImpl implements AdminBiz { if (log == null) { return new ReturnT(ReturnT.FAIL_CODE, "log item not found."); } + if (log.getHandleCode() > 0) { + return new ReturnT(ReturnT.FAIL_CODE, "log repeate callback."); // avoid repeat callback, trigger child job etc + } - // trigger success, to trigger child job, and avoid repeat trigger child job - String childTriggerMsg = null; - if (ReturnT.SUCCESS_CODE==handleCallbackParam.getExecuteResult().getCode() && ReturnT.SUCCESS_CODE!=log.getHandleCode()) { + // trigger success, to trigger child job + String callbackMsg = null; + if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) { XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId()); - if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobKey())) { - childTriggerMsg = "
"; - String[] childJobKeys = xxlJobInfo.getChildJobKey().split(","); - for (int i = 0; i < childJobKeys.length; i++) { - String[] jobKeyArr = childJobKeys[i].split("_"); - if (jobKeyArr!=null && jobKeyArr.length==2) { - ReturnT triggerChildResult = xxlJobService.triggerJob(Integer.valueOf(jobKeyArr[1])); + if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) { + callbackMsg = "

>>>>>>>>>>>触发子任务<<<<<<<<<<<
"; + + String[] childJobIds = xxlJobInfo.getChildJobId().split(","); + for (int i = 0; i < childJobIds.length; i++) { + int childJobId = (StringUtils.isNotBlank(childJobIds[i]) && StringUtils.isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1; + if (childJobId > 0) { + ReturnT triggerChildResult = xxlJobService.triggerJob(childJobId); + // add msg - childTriggerMsg += MessageFormat.format("
{0}/{1} 触发子任务{2}, 子任务Key: {3}, 子任务触发备注: {4}", - (i+1), childJobKeys.length, (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), childJobKeys[i], triggerChildResult.getMsg()); + callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4}
", + (i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); } else { - childTriggerMsg += MessageFormat.format("
{0}/{1} 触发子任务失败, 子任务Key格式错误, 子任务Key: {2}", - (i+1), childJobKeys.length, childJobKeys[i]); + callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误
", + (i+1), childJobIds.length, childJobIds[i]); } } } + } else if (IJobHandler.FAIL_RETRY.getCode() == handleCallbackParam.getExecuteResult().getCode()){ + ReturnT retryTriggerResult = xxlJobService.triggerJob(log.getJobId()); + callbackMsg = "

>>>>>>>>>>>执行失败重试<<<<<<<<<<<
"; + + callbackMsg += MessageFormat.format("触发{0}, 触发备注: {1}", + (retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), retryTriggerResult.getMsg()); } // handle msg @@ -90,8 +98,8 @@ public class AdminBizImpl implements AdminBiz { if (handleCallbackParam.getExecuteResult().getMsg() != null) { handleMsg.append(handleCallbackParam.getExecuteResult().getMsg()); } - if (childTriggerMsg !=null) { - handleMsg.append("
子任务触发备注:").append(childTriggerMsg); + if (callbackMsg != null) { + handleMsg.append(callbackMsg); } // success, save log diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java index 2eccb310..eecef342 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java @@ -13,10 +13,10 @@ import com.xxl.job.admin.service.XxlJobService; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; import com.xxl.job.core.glue.GlueTypeEnum; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.time.DateUtils; -import org.apache.commons.lang.time.FastDateFormat; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateUtils; +import org.apache.commons.lang3.time.FastDateFormat; import org.quartz.CronExpression; import org.quartz.SchedulerException; import org.slf4j.Logger; @@ -103,19 +103,20 @@ public class XxlJobServiceImpl implements XxlJobService { jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", "")); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - String[] childJobKeyArr = childJobKeyItem.split("_"); - if (childJobKeyArr.length!=2) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobKeyArr[1])); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // add in db @@ -166,19 +167,24 @@ public class XxlJobServiceImpl implements XxlJobService { return new ReturnT(ReturnT.FAIL_CODE, "失败处理策略非法"); } - // childJobKey valid - if (StringUtils.isNotBlank(jobInfo.getChildJobKey())) { - String[] childJobKeys = jobInfo.getChildJobKey().split(","); - for (String childJobKeyItem: childJobKeys) { - String[] childJobKeyArr = childJobKeyItem.split("_"); - if (childJobKeyArr.length!=2) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})格式错误", childJobKeyItem)); - } - XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobKeyArr[1])); - if (childJobInfo==null) { - return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务Key({0})无效", childJobKeyItem)); + // ChildJobId valid + if (StringUtils.isNotBlank(jobInfo.getChildJobId())) { + String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ","); + for (String childJobIdItem: childJobIds) { + if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem)); + if (childJobInfo==null) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem)); + } + // avoid cycle relate + if (childJobInfo.getId() == jobInfo.getId()) { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})不可与父任务重复", childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem)); } } + jobInfo.setChildJobId(StringUtils.join(childJobIds, ",")); } // stage job info @@ -197,7 +203,7 @@ public class XxlJobServiceImpl implements XxlJobService { exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam()); exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy()); - exists_jobInfo.setChildJobKey(jobInfo.getChildJobKey()); + exists_jobInfo.setChildJobId(jobInfo.getChildJobId()); xxlJobInfoDao.update(exists_jobInfo); // fresh quartz diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml index 9be9b8e0..a5c3abd0 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml @@ -27,7 +27,7 @@ - + @@ -48,7 +48,7 @@ t.glue_source, t.glue_remark, t.glue_updatetime, - t.child_jobkey + t.child_jobid - -
+
+ +
diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.index.ftl index d77d86d5..66bb1be4 100644 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.index.ftl +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.index.ftl @@ -90,10 +90,8 @@ - + - - <#----> diff --git a/xxl-job-admin/src/main/webapp/static/js/common.1.js b/xxl-job-admin/src/main/webapp/static/js/common.1.js index 515325f5..b11af37a 100644 --- a/xxl-job-admin/src/main/webapp/static/js/common.1.js +++ b/xxl-job-admin/src/main/webapp/static/js/common.1.js @@ -7,14 +7,18 @@ $(function(){ $.post(base_url + "/logout", function(data, status) { if (data.code == "200") { - layer.open({ + layer.msg('注销成功'); + setTimeout(function(){ + window.location.href = base_url + "/"; + }, 500); + /*layer.open({ title: '系统提示', content: '注销成功', icon: '1', end: function(layero, index){ window.location.href = base_url + "/"; } - }); + });*/ } else { layer.open({ title: '系统提示', diff --git a/xxl-job-admin/src/main/webapp/static/js/jobgroup.index.1.js b/xxl-job-admin/src/main/webapp/static/js/jobgroup.index.1.js index c3b8181d..0e0b38fd 100644 --- a/xxl-job-admin/src/main/webapp/static/js/jobgroup.index.1.js +++ b/xxl-job-admin/src/main/webapp/static/js/jobgroup.index.1.js @@ -122,11 +122,13 @@ $(function() { // 注册方式,切换 $("#addModal input[name=addressType], #updateModal input[name=addressType]").click(function(){ var addressType = $(this).val(); - var $addressList = $(this).parents("form").find("input[name=addressList]"); + var $addressList = $(this).parents("form").find("textarea[name=addressList]"); if (addressType == 0) { + $addressList.css("background-color", "#eee"); // 自动注册 + $addressList.attr("readonly","readonly"); $addressList.val(""); - $addressList.attr("readonly","readonly"); } else { + $addressList.css("background-color", "white"); $addressList.removeAttr("readonly"); } }); @@ -144,7 +146,7 @@ $(function() { //$("#updateModal .form input[name='addressType'][value='"+ addressType +"']").attr('checked', 'true'); $("#updateModal .form input[name='addressType'][value='"+ addressType +"']").click(); // 机器地址 - $("#updateModal .form input[name='addressList']").val($(this).attr("addressList")); + $("#updateModal .form textarea[name='addressList']").val($(this).attr("addressList")); $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); }); diff --git a/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js b/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js index eccd6ca6..74d88fc2 100644 --- a/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js +++ b/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js @@ -20,7 +20,7 @@ $(function() { "ordering": false, //"scrollX": true, // X轴滚动条,取消自适应 "columns": [ - { "data": 'id', "bSortable": false, "visible" : false}, + { "data": 'id', "bSortable": false, "visible" : true}, { "data": 'jobGroup', "visible" : false, @@ -34,15 +34,6 @@ $(function() { return data; } }, - { - "data": 'childJobKey', - "width":'10%', - "visible" : true, - "render": function ( data, type, row ) { - var jobKey = row.jobGroup + "_" + row.id; - return jobKey; - } - }, { "data": 'jobDesc', "visible" : true,"width":'20%'}, { "data": 'glueType', @@ -372,7 +363,7 @@ $(function() { $('#updateModal .form select[name=executorRouteStrategy] option[value='+ row.executorRouteStrategy +']').prop('selected', true); $("#updateModal .form input[name='executorHandler']").val( row.executorHandler ); $("#updateModal .form input[name='executorParam']").val( row.executorParam ); - $("#updateModal .form input[name='childJobKey']").val( row.childJobKey ); + $("#updateModal .form input[name='childJobId']").val( row.childJobId ); $('#updateModal .form select[name=executorBlockStrategy] option[value='+ row.executorBlockStrategy +']').prop('selected', true); $('#updateModal .form select[name=executorFailStrategy] option[value='+ row.executorFailStrategy +']').prop('selected', true); $('#updateModal .form select[name=glueType] option[value='+ row.glueType +']').prop('selected', true); diff --git a/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js b/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js index ff33f400..fb7aa64e 100644 --- a/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js +++ b/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js @@ -89,54 +89,32 @@ $(function() { "ordering": false, //"scrollX": false, "columns": [ - { "data": 'id', "bSortable": false, "visible" : false}, - { "data": 'jobGroup', "visible" : false}, - { "data": 'jobId', "visible" : false}, { - "data": 'JobKey', + "data": 'jobId', "visible" : true, "render": function ( data, type, row ) { - var jobKey = row.jobGroup + "_" + row.jobId; - - var glueTypeTitle = row.glueType; - if ('GLUE_GROOVY'==row.glueType) { - glueTypeTitle = "GLUE模式(Java)"; - } else if ('GLUE_SHELL'==row.glueType) { - glueTypeTitle = "GLUE模式(Shell)"; - } else if ('GLUE_PYTHON'==row.glueType) { - glueTypeTitle = "GLUE模式(Python)"; - }else if ('GLUE_NODEJS'==row.glueType) { - glueTypeTitle = "GLUE模式(Nodejs)"; - } else if ('BEAN'==row.glueType) { - glueTypeTitle = "BEAN模式:" + row.executorHandler; - } + var glueTypeTitle = row.glueType; + if ('GLUE_GROOVY'==row.glueType) { + glueTypeTitle = "GLUE模式(Java)"; + } else if ('GLUE_SHELL'==row.glueType) { + glueTypeTitle = "GLUE模式(Shell)"; + } else if ('GLUE_PYTHON'==row.glueType) { + glueTypeTitle = "GLUE模式(Python)"; + }else if ('GLUE_NODEJS'==row.glueType) { + glueTypeTitle = "GLUE模式(Nodejs)"; + } else if ('BEAN'==row.glueType) { + glueTypeTitle = "BEAN模式:" + row.executorHandler; + } - var temp = ''; - temp += '执行器地址:' + (row.executorAddress?row.executorAddress:''); - temp += '
运行模式:' + glueTypeTitle; - temp += '
任务参数:' + row.executorParam; + var temp = ''; + temp += '执行器地址:' + (row.executorAddress?row.executorAddress:''); + temp += '
运行模式:' + glueTypeTitle; + temp += '
任务参数:' + row.executorParam; - return ''+ jobKey +''+ temp +''; + return ''+ row.jobId +''+ temp +''; } }, - // { "data": 'executorAddress', "visible" : true}, - // { - // "data": 'glueType', - // "visible" : true, - // "render": function ( data, type, row ) { - // if ('GLUE_GROOVY'==row.glueType) { - // return "GLUE模式(Java)"; - // } else if ('GLUE_SHELL'==row.glueType) { - // return "GLUE模式(Shell)"; - // } else if ('GLUE_PYTHON'==row.glueType) { - // return "GLUE模式(Python)"; - // } else if ('BEAN'==row.glueType) { - // return "BEAN模式:" + row.executorHandler; - // } - // return row.executorHandler; - // } - // }, - // { "data": 'executorParam', "visible" : true}, + { "data": 'jobGroup', "visible" : false}, { "data": 'triggerTime', "render": function ( data, type, row ) { @@ -146,9 +124,16 @@ $(function() { { "data": 'triggerCode', "render": function ( data, type, row ) { - return (data==200)?'成功':(data==500)?'失败':(data==0)?'':data; + var html = data; + if (data == 200) { + html = '成功'; + } else if (data == 500) { + html = '失败'; + } else if (data == 0) { + html = ''; + } + return html; } - }, { "data": 'triggerMsg', @@ -165,7 +150,17 @@ $(function() { { "data": 'handleCode', "render": function ( data, type, row ) { - return (data==200)?'成功':(data==500)?'失败':(data==0)?'':data; + var html = data; + if (data == 200) { + html = '成功'; + } else if (data == 500) { + html = '失败'; + } else if (data == 501) { + html = '失败重试'; + } else if (data == 0) { + html = ''; + } + return html; } }, { diff --git a/xxl-job-admin/src/main/webapp/static/js/login.1.js b/xxl-job-admin/src/main/webapp/static/js/login.1.js index 67bd6cac..6300cdbc 100644 --- a/xxl-job-admin/src/main/webapp/static/js/login.1.js +++ b/xxl-job-admin/src/main/webapp/static/js/login.1.js @@ -48,14 +48,18 @@ $(function(){ submitHandler : function(form) { $.post(base_url + "/login", $("#loginForm").serialize(), function(data, status) { if (data.code == "200") { - layer.open({ + layer.msg('登录成功'); + setTimeout(function(){ + window.location.href = base_url; + }, 500); + /*layer.open({ title: '系统提示', content: '登录成功', icon: '1', end: function(layero, index){ window.location.href = base_url; } - }); + });*/ } else { layer.open({ title: '系统提示', diff --git a/xxl-job-admin/src/test/java/com/xxl/job/admin/controller/AbstractSpringMvcTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/controller/AbstractSpringMvcTest.java new file mode 100644 index 00000000..bb156206 --- /dev/null +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/controller/AbstractSpringMvcTest.java @@ -0,0 +1,27 @@ +package com.xxl.job.admin.controller; + +import org.junit.Before; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@WebAppConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"classpath*:spring/*.xml"}) +public class AbstractSpringMvcTest { + + @Autowired + private WebApplicationContext applicationContext; + protected MockMvc mockMvc; + + @Before + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.applicationContext).build(); + } + +} diff --git a/xxl-job-admin/src/test/java/com/xxl/job/admin/controller/JobInfoControllerTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/controller/JobInfoControllerTest.java new file mode 100644 index 00000000..8da5fda3 --- /dev/null +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/controller/JobInfoControllerTest.java @@ -0,0 +1,47 @@ +package com.xxl.job.admin.controller; + +import com.xxl.job.admin.controller.interceptor.PermissionInterceptor; +import com.xxl.job.admin.core.util.PropertiesUtil; +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import javax.servlet.http.Cookie; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; + +public class JobInfoControllerTest extends AbstractSpringMvcTest { + + private Cookie cookie; + + @Before + public void login() throws Exception { + MvcResult ret = mockMvc.perform( + post("/login") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param("userName", PropertiesUtil.getString("xxl.job.login.username")) + .param("password", PropertiesUtil.getString("xxl.job.login.password")) + ).andReturn(); + cookie = ret.getResponse().getCookie(PermissionInterceptor.LOGIN_IDENTITY_KEY); + } + + @Test + public void testAdd() throws Exception { + MultiValueMap parameters = new LinkedMultiValueMap(); + parameters.add("jobGroup", "1"); + + MvcResult ret = mockMvc.perform( + post("/jobinfo/pageList") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + //.content(paramsJson) + .params(parameters) + .cookie(cookie) + ).andReturn(); + + System.out.println(ret.getResponse().getContentAsString()); + } + +} diff --git a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobGroupDaoTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobGroupDaoTest.java similarity index 97% rename from xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobGroupDaoTest.java rename to xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobGroupDaoTest.java index 122d4780..5b99178f 100644 --- a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobGroupDaoTest.java +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobGroupDaoTest.java @@ -1,4 +1,4 @@ -package com.xxl.job.dao.impl; +package com.xxl.job.admin.dao; import com.xxl.job.admin.core.model.XxlJobGroup; import com.xxl.job.admin.dao.XxlJobGroupDao; diff --git a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobInfoTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java similarity index 91% rename from xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobInfoTest.java rename to xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java index d7d17d2d..87c4de9e 100644 --- a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobInfoTest.java +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java @@ -1,78 +1,78 @@ -package com.xxl.job.dao.impl; - -import com.xxl.job.admin.core.model.XxlJobInfo; -import com.xxl.job.admin.dao.XxlJobInfoDao; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import javax.annotation.Resource; -import java.util.Date; -import java.util.List; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = "classpath*:spring/applicationcontext-*.xml") -public class XxlJobInfoTest { - - @Resource - private XxlJobInfoDao xxlJobInfoDao; - - @Test - public void pageList(){ - List list = xxlJobInfoDao.pageList(0, 20, 0, null); - int list_count = xxlJobInfoDao.pageListCount(0, 20, 0, null); - - System.out.println(list); - System.out.println(list_count); - - List list2 = xxlJobInfoDao.getJobsByGroup(1); - } - - @Test - public void save_load(){ - XxlJobInfo info = new XxlJobInfo(); - info.setJobGroup(1); - info.setJobCron("jobCron"); - info.setJobDesc("desc"); - info.setAuthor("setAuthor"); - info.setAlarmEmail("setAlarmEmail"); - info.setExecutorRouteStrategy("setExecutorRouteStrategy"); - info.setExecutorHandler("setExecutorHandler"); - info.setExecutorParam("setExecutorParam"); - info.setExecutorBlockStrategy("setExecutorBlockStrategy"); - info.setExecutorFailStrategy("setExecutorFailStrategy"); - info.setGlueType("setGlueType"); - info.setGlueSource("setGlueSource"); - info.setGlueRemark("setGlueRemark"); - info.setChildJobKey("setChildJobKey"); - - int count = xxlJobInfoDao.save(info); - - XxlJobInfo info2 = xxlJobInfoDao.loadById(info.getId()); - info2.setJobCron("jobCron2"); - info2.setJobDesc("desc2"); - info2.setAuthor("setAuthor2"); - info2.setAlarmEmail("setAlarmEmail2"); - info2.setExecutorRouteStrategy("setExecutorRouteStrategy2"); - info2.setExecutorHandler("setExecutorHandler2"); - info2.setExecutorParam("setExecutorParam2"); - info2.setExecutorBlockStrategy("setExecutorBlockStrategy2"); - info2.setExecutorFailStrategy("setExecutorFailStrategy2"); - info2.setGlueType("setGlueType2"); - info2.setGlueSource("setGlueSource2"); - info2.setGlueRemark("setGlueRemark2"); - info2.setGlueUpdatetime(new Date()); - info2.setChildJobKey("setChildJobKey2"); - - int item2 = xxlJobInfoDao.update(info2); - - xxlJobInfoDao.delete(info2.getId()); - - List list2 = xxlJobInfoDao.getJobsByGroup(1); - - int ret3 = xxlJobInfoDao.findAllCount(); - - } - -} +package com.xxl.job.admin.dao; + +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.dao.XxlJobInfoDao; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = "classpath*:spring/applicationcontext-*.xml") +public class XxlJobInfoDaoTest { + + @Resource + private XxlJobInfoDao xxlJobInfoDao; + + @Test + public void pageList(){ + List list = xxlJobInfoDao.pageList(0, 20, 0, null); + int list_count = xxlJobInfoDao.pageListCount(0, 20, 0, null); + + System.out.println(list); + System.out.println(list_count); + + List list2 = xxlJobInfoDao.getJobsByGroup(1); + } + + @Test + public void save_load(){ + XxlJobInfo info = new XxlJobInfo(); + info.setJobGroup(1); + info.setJobCron("jobCron"); + info.setJobDesc("desc"); + info.setAuthor("setAuthor"); + info.setAlarmEmail("setAlarmEmail"); + info.setExecutorRouteStrategy("setExecutorRouteStrategy"); + info.setExecutorHandler("setExecutorHandler"); + info.setExecutorParam("setExecutorParam"); + info.setExecutorBlockStrategy("setExecutorBlockStrategy"); + info.setExecutorFailStrategy("setExecutorFailStrategy"); + info.setGlueType("setGlueType"); + info.setGlueSource("setGlueSource"); + info.setGlueRemark("setGlueRemark"); + info.setChildJobId("1"); + + int count = xxlJobInfoDao.save(info); + + XxlJobInfo info2 = xxlJobInfoDao.loadById(info.getId()); + info2.setJobCron("jobCron2"); + info2.setJobDesc("desc2"); + info2.setAuthor("setAuthor2"); + info2.setAlarmEmail("setAlarmEmail2"); + info2.setExecutorRouteStrategy("setExecutorRouteStrategy2"); + info2.setExecutorHandler("setExecutorHandler2"); + info2.setExecutorParam("setExecutorParam2"); + info2.setExecutorBlockStrategy("setExecutorBlockStrategy2"); + info2.setExecutorFailStrategy("setExecutorFailStrategy2"); + info2.setGlueType("setGlueType2"); + info2.setGlueSource("setGlueSource2"); + info2.setGlueRemark("setGlueRemark2"); + info2.setGlueUpdatetime(new Date()); + info2.setChildJobId("1"); + + int item2 = xxlJobInfoDao.update(info2); + + xxlJobInfoDao.delete(info2.getId()); + + List list2 = xxlJobInfoDao.getJobsByGroup(1); + + int ret3 = xxlJobInfoDao.findAllCount(); + + } + +} diff --git a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogDaoTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogDaoTest.java similarity index 95% rename from xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogDaoTest.java rename to xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogDaoTest.java index b8c56e23..02652bbc 100644 --- a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogDaoTest.java +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogDaoTest.java @@ -1,8 +1,8 @@ -package com.xxl.job.dao.impl; +package com.xxl.job.admin.dao; import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.dao.XxlJobLogDao; -import org.apache.commons.lang.time.DateUtils; +import org.apache.commons.lang3.time.DateUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; diff --git a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogGlueDaoTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogGlueDaoTest.java similarity index 97% rename from xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogGlueDaoTest.java rename to xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogGlueDaoTest.java index fe8ebc8a..a4adc444 100644 --- a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogGlueDaoTest.java +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogGlueDaoTest.java @@ -1,4 +1,4 @@ -package com.xxl.job.dao.impl; +package com.xxl.job.admin.dao; import com.xxl.job.admin.core.model.XxlJobLogGlue; import com.xxl.job.admin.dao.XxlJobLogGlueDao; diff --git a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobRegistryDaoTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobRegistryDaoTest.java similarity index 96% rename from xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobRegistryDaoTest.java rename to xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobRegistryDaoTest.java index 349ef4b0..69448727 100644 --- a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobRegistryDaoTest.java +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobRegistryDaoTest.java @@ -1,4 +1,4 @@ -package com.xxl.job.dao.impl; +package com.xxl.job.admin.dao; import com.xxl.job.admin.core.model.XxlJobRegistry; import com.xxl.job.admin.dao.XxlJobRegistryDao; diff --git a/xxl-job-admin/src/test/java/com/xxl/job/admin/util/MailUtilTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/util/MailUtilTest.java new file mode 100644 index 00000000..3821818b --- /dev/null +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/util/MailUtilTest.java @@ -0,0 +1,45 @@ +package com.xxl.job.admin.util; + +import com.xxl.job.admin.core.util.MailUtil; +import org.junit.Test; + +import java.text.MessageFormat; + +/** + * email util test + * + * @author xuxueli 2017-12-22 17:16:23 + */ +public class MailUtilTest { + + @Test + public void registryTest() throws Exception { + + String mailBodyTemplate = "
监控告警明细:" + + "
id任务ID 执行器ID任务IDJobKey执行器地址 运行模式 任务参数
\n" + + " " + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
执行器任务ID任务描述告警类型
{0}{1}{2}调度失败
"; + + String title = "调度中心监控报警"; + String content = MessageFormat.format(mailBodyTemplate, "执行器A", "01", "任务A1"); + + boolean ret = MailUtil.sendMail("931591021@qq.com", title, content); + System.out.println(ret); + } + +} diff --git a/xxl-job-admin/src/test/java/com/xxl/job/admin/util/PropertiesUtilTest.java b/xxl-job-admin/src/test/java/com/xxl/job/admin/util/PropertiesUtilTest.java new file mode 100644 index 00000000..5c8b7f04 --- /dev/null +++ b/xxl-job-admin/src/test/java/com/xxl/job/admin/util/PropertiesUtilTest.java @@ -0,0 +1,18 @@ +package com.xxl.job.admin.util; + +import com.xxl.job.admin.core.util.PropertiesUtil; +import org.junit.Test; + +/** + * prop util test + * + * @author xuxueli 2017-12-25 15:17:36 + */ +public class PropertiesUtilTest { + + @Test + public void registryTest() throws Exception { + System.out.println(PropertiesUtil.getString("xxl.job.login.username")); + } + +} diff --git a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/AdminBizTest.java b/xxl-job-admin/src/test/java/com/xxl/job/adminbiz/AdminBizTest.java similarity index 98% rename from xxl-job-admin/src/test/java/com/xxl/job/dao/impl/AdminBizTest.java rename to xxl-job-admin/src/test/java/com/xxl/job/adminbiz/AdminBizTest.java index 6ccea517..ae2f559d 100644 --- a/xxl-job-admin/src/test/java/com/xxl/job/dao/impl/AdminBizTest.java +++ b/xxl-job-admin/src/test/java/com/xxl/job/adminbiz/AdminBizTest.java @@ -1,4 +1,4 @@ -package com.xxl.job.dao.impl; +package com.xxl.job.adminbiz; import com.xxl.job.core.biz.AdminBiz; import com.xxl.job.core.biz.model.RegistryParam; diff --git a/xxl-job-core/pom.xml b/xxl-job-core/pom.xml index bcc684ae..a46a61b1 100644 --- a/xxl-job-core/pom.xml +++ b/xxl-job-core/pom.xml @@ -49,11 +49,11 @@ - org.codehaus.jackson - jackson-mapper-asl - ${jackson-mapper-asl.version} + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} - + org.apache.httpcomponents diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java b/xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java index 5fc3ea7e..885ae3f9 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java @@ -59,7 +59,7 @@ public class ExecutorBizImpl implements ExecutorBiz { @Override public ReturnT log(long logDateTim, int logId, int fromLineNum) { - // log filename: yyyy-MM-dd/9999.log + // log filename: logPath/yyyy-MM-dd/9999.log String logFileName = XxlJobFileAppender.makeLogFileName(new Date(logDateTim), logId); LogResult logResult = XxlJobFileAppender.readLog(logFileName, fromLineNum); @@ -74,7 +74,8 @@ public class ExecutorBizImpl implements ExecutorBiz { String removeOldReason = null; // valid:jobHandler + jobThread - if (GlueTypeEnum.BEAN==GlueTypeEnum.match(triggerParam.getGlueType())) { + GlueTypeEnum glueTypeEnum = GlueTypeEnum.match(triggerParam.getGlueType()); + if (GlueTypeEnum.BEAN == glueTypeEnum) { // new jobhandler IJobHandler newJobHandler = XxlJobExecutor.loadJobHandler(triggerParam.getExecutorHandler()); @@ -96,7 +97,7 @@ public class ExecutorBizImpl implements ExecutorBiz { } } - } else if (GlueTypeEnum.GLUE_GROOVY==GlueTypeEnum.match(triggerParam.getGlueType())) { + } else if (GlueTypeEnum.GLUE_GROOVY == glueTypeEnum) { // valid old jobThread if (jobThread != null && @@ -119,9 +120,7 @@ public class ExecutorBizImpl implements ExecutorBiz { return new ReturnT(ReturnT.FAIL_CODE, e.getMessage()); } } - } else if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(triggerParam.getGlueType()) - || GlueTypeEnum.GLUE_PYTHON==GlueTypeEnum.match(triggerParam.getGlueType()) - || GlueTypeEnum.GLUE_NODEJS==GlueTypeEnum.match(triggerParam.getGlueType())) { + } else if (glueTypeEnum!=null && glueTypeEnum.isScript()) { // valid old jobThread if (jobThread != null && diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java b/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java index 4ecb461c..f58853c1 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java @@ -72,14 +72,10 @@ public class XxlJobExecutor implements ApplicationContextAware { initAdminBizList(adminAddresses, accessToken); // init executor-jobHandlerRepository - if (applicationContext != null) { - initJobHandlerRepository(applicationContext); - } + initJobHandlerRepository(applicationContext); // init logpath - if (logPath!=null && logPath.trim().length()>0) { - XxlJobFileAppender.logPath = logPath; - } + XxlJobFileAppender.initLogPath(logPath); // init executor-server initExecutorServer(port, ip, appName, accessToken); @@ -145,6 +141,10 @@ public class XxlJobExecutor implements ApplicationContextAware { return jobHandlerRepository.get(name); } private static void initJobHandlerRepository(ApplicationContext applicationContext){ + if (applicationContext == null) { + return; + } + // init job handler action Map serviceBeanMap = applicationContext.getBeansWithAnnotation(JobHandler.class); diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java b/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java index 17ab97ae..c60ddf44 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/glue/GlueTypeEnum.java @@ -5,20 +5,40 @@ package com.xxl.job.core.glue; */ public enum GlueTypeEnum { - BEAN("BEAN模式"), - GLUE_GROOVY("GLUE模式(Java)"), - GLUE_SHELL("GLUE模式(Shell)"), - GLUE_PYTHON("GLUE模式(Python)"), - GLUE_NODEJS("GLUE模式(Nodejs)"); + BEAN("BEAN模式", false, null, null), + GLUE_GROOVY("GLUE模式(Java)", false, null, null), + GLUE_SHELL("GLUE模式(Shell)", true, "bash", ".sh"), + GLUE_PYTHON("GLUE模式(Python)", true, "python", ".py"), + GLUE_NODEJS("GLUE模式(Nodejs)", true, "node", ".js"); private String desc; - private GlueTypeEnum(String desc) { + private boolean isScript; + private String cmd; + private String suffix; + + private GlueTypeEnum(String desc, boolean isScript, String cmd, String suffix) { this.desc = desc; + this.isScript = isScript; + this.cmd = cmd; + this.suffix = suffix; } + public String getDesc() { return desc; } + public boolean isScript() { + return isScript; + } + + public String getCmd() { + return cmd; + } + + public String getSuffix() { + return suffix; + } + public static GlueTypeEnum match(String name){ for (GlueTypeEnum item: GlueTypeEnum.values()) { if (item.name().equals(name)) { @@ -27,4 +47,5 @@ public enum GlueTypeEnum { } return null; } + } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java index 246068ef..fd1d0b12 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/IJobHandler.java @@ -3,17 +3,45 @@ package com.xxl.job.core.handler; import com.xxl.job.core.biz.model.ReturnT; /** - * remote job handler + * job handler + * * @author xuxueli 2015-12-19 19:06:38 */ public abstract class IJobHandler { + + /** success */ + public static final ReturnT SUCCESS = new ReturnT(200, null); + /** fail */ + public static final ReturnT FAIL = new ReturnT(500, null); + /** fail retry */ + public static final ReturnT FAIL_RETRY = new ReturnT(501, null); + + /** - * job handler - * @param params + * execute handler, invoked when executor receives a scheduling request + * + * @param param * @return * @throws Exception */ - public abstract ReturnT execute(String... params) throws Exception; - + public abstract ReturnT execute(String param) throws Exception; + + + /** + * init handler, invoked when JobThread init + */ + public void init() { + // TODO + } + + + /** + * destroy handler, invoked when JobThread destroy + */ + public void destroy() { + // TODO + } + + } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java index a0539fd8..3dc91a22 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/GlueJobHandler.java @@ -21,9 +21,9 @@ public class GlueJobHandler extends IJobHandler { } @Override - public ReturnT execute(String... params) throws Exception { + public ReturnT execute(String param) throws Exception { XxlJobLogger.log("----------- glue.version:"+ glueUpdatetime +" -----------"); - return jobHandler.execute(params); + return jobHandler.execute(param); } } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java index 63fdc8cd..038eec44 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java @@ -6,6 +6,7 @@ import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.log.XxlJobFileAppender; import com.xxl.job.core.log.XxlJobLogger; import com.xxl.job.core.util.ScriptUtil; +import com.xxl.job.core.util.ShardingUtil; /** * Created by xuxueli on 17/4/27. @@ -29,32 +30,38 @@ public class ScriptJobHandler extends IJobHandler { } @Override - public ReturnT execute(String... params) throws Exception { - - // cmd + script-file-name - String cmd = "bash"; - String scriptFileName = null; - if (GlueTypeEnum.GLUE_SHELL == glueType) { - cmd = "bash"; - scriptFileName = XxlJobFileAppender.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".sh"); - } else if (GlueTypeEnum.GLUE_PYTHON == glueType) { - cmd = "python"; - scriptFileName = XxlJobFileAppender.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".py"); - } else if (GlueTypeEnum.GLUE_NODEJS == glueType) { - cmd = "node"; - scriptFileName = XxlJobFileAppender.logPath.concat("gluesource/").concat(String.valueOf(jobId)).concat("_").concat(String.valueOf(glueUpdatetime)).concat(".js"); + public ReturnT execute(String param) throws Exception { + + if (!glueType.isScript()) { + return new ReturnT(IJobHandler.FAIL.getCode(), "glueType["+ glueType +"] invalid."); } + // cmd + String cmd = glueType.getCmd(); + // make script file + String scriptFileName = XxlJobFileAppender.getLogPath() + .concat("/gluesource/") + .concat(String.valueOf(jobId)) + .concat("_") + .concat(String.valueOf(glueUpdatetime)) + .concat(glueType.getSuffix()); ScriptUtil.markScriptFile(scriptFileName, gluesource); // log file - String logFileName = XxlJobFileAppender.logPath.concat(XxlJobFileAppender.contextHolder.get()); + String logFileName = XxlJobFileAppender.contextHolder.get(); + + // script params:0=param、1=分片序号、2=分片总数 + ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo(); + String[] scriptParams = new String[3]; + scriptParams[0] = param; + scriptParams[1] = String.valueOf(shardingVO.getIndex()); + scriptParams[2] = String.valueOf(shardingVO.getTotal()); // invoke XxlJobLogger.log("----------- script file:"+ scriptFileName +" -----------"); - int exitValue = ScriptUtil.execToFile(cmd, scriptFileName, logFileName, params); - ReturnT result = (exitValue==0)?ReturnT.SUCCESS:new ReturnT(ReturnT.FAIL_CODE, "script exit value("+exitValue+") is failed"); + int exitValue = ScriptUtil.execToFile(cmd, scriptFileName, logFileName, scriptParams); + ReturnT result = (exitValue==0)?IJobHandler.SUCCESS:new ReturnT(IJobHandler.FAIL.getCode(), "script exit value("+exitValue+") is failed"); return result; } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java b/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java index 2ed2f7fa..0e9dcc23 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java @@ -18,10 +18,35 @@ public class XxlJobFileAppender { // for JobThread (support log for child thread of job handler) //public static ThreadLocal contextHolder = new ThreadLocal(); public static final InheritableThreadLocal contextHolder = new InheritableThreadLocal(); - public static String logPath = "/data/applogs/xxl-job/jobhandler/"; + + + // log base path + private static String logBasePath = "/data/applogs/xxl-job/jobhandler"; + public static void initLogPath(String logPath){ + // init + if (logPath!=null && logPath.trim().length()>0) { + logBasePath = logPath; + } + // mk base dir + File logPathDir = new File(logBasePath); + if (!logPathDir.exists()) { + logPathDir.mkdirs(); + } + logBasePath = logPathDir.getPath(); + + // mk glue dir + File glueBaseDir = new File(logPathDir, "gluesource"); + if (!glueBaseDir.exists()) { + glueBaseDir.mkdirs(); + } + } + public static String getLogPath() { + return logBasePath; + } + /** - * log filename: yyyy-MM-dd/9999.log + * log filename, like "logPath/yyyy-MM-dd/9999.log" * * @param triggerDate * @param logId @@ -29,23 +54,18 @@ public class XxlJobFileAppender { */ public static String makeLogFileName(Date triggerDate, int logId) { - // filePath/ - File filePathDir = new File(logPath); - if (!filePathDir.exists()) { - filePathDir.mkdirs(); - } - - // filePath/yyyy-MM-dd/ + // filePath/yyyy-MM-dd SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // avoid concurrent problem, can not be static + File logFilePath = new File(getLogPath(), sdf.format(triggerDate)); + if (!logFilePath.exists()) { + logFilePath.mkdir(); + } - String nowFormat = sdf.format(new Date()); - File filePathDateDir = new File(filePathDir, nowFormat); - if (!filePathDateDir.exists()) { - filePathDateDir.mkdirs(); - } - - // filePath/yyyy-MM-dd/9999.log - String logFileName = sdf.format(triggerDate).concat("/").concat(String.valueOf(logId)).concat(".log"); + // filePath/yyyy-MM-dd/9999.log + String logFileName = logFilePath.getPath() + .concat("/") + .concat(String.valueOf(logId)) + .concat(".log"); return logFileName; } @@ -57,17 +77,11 @@ public class XxlJobFileAppender { */ public static void appendLog(String logFileName, String appendLog) { - // log - if (appendLog == null) { - appendLog = ""; - } - appendLog += "\r\n"; - // log file if (logFileName==null || logFileName.trim().length()==0) { return; } - File logFile = new File(logPath, logFileName); + File logFile = new File(logFileName); if (!logFile.exists()) { try { @@ -77,6 +91,12 @@ public class XxlJobFileAppender { return; } } + + // log + if (appendLog == null) { + appendLog = ""; + } + appendLog += "\r\n"; // append file content try { @@ -112,7 +132,7 @@ public class XxlJobFileAppender { if (logFileName==null || logFileName.trim().length()==0) { return new LogResult(fromLineNum, 0, "readLog fail, logFile not found", true); } - File logFile = new File(logPath, logFileName); + File logFile = new File(logFileName); if (!logFile.exists()) { return new LogResult(fromLineNum, 0, "readLog fail, logFile not exists", true); diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobLogger.java b/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobLogger.java index f9b970ca..248d9de0 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobLogger.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobLogger.java @@ -3,6 +3,8 @@ package com.xxl.job.core.log; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.PrintWriter; +import java.io.StringWriter; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -17,46 +19,63 @@ public class XxlJobLogger { /** * append log * + * @param callInfo * @param appendLog */ - public static void log(String appendLog) { + private static void logDetail(StackTraceElement callInfo, String appendLog) { - // logFileName - String logFileName = XxlJobFileAppender.contextHolder.get(); - if (logFileName==null || logFileName.trim().length()==0) { - return; - } - // "yyyy-MM-dd HH:mm:ss [ClassName]-[MethodName]-[LineNumber]-[ThreadName] log"; + /*// "yyyy-MM-dd HH:mm:ss [ClassName]-[MethodName]-[LineNumber]-[ThreadName] log"; StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - StackTraceElement callInfo = stackTraceElements[1]; + StackTraceElement callInfo = stackTraceElements[1];*/ StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(xxlJobLoggerFormat.format(new Date())).append(" ") - .append("["+ callInfo.getClassName() +"]").append("-") - .append("["+ callInfo.getMethodName() +"]").append("-") + .append("["+ callInfo.getClassName() + "#" + callInfo.getMethodName() +"]").append("-") .append("["+ callInfo.getLineNumber() +"]").append("-") .append("["+ Thread.currentThread().getName() +"]").append(" ") .append(appendLog!=null?appendLog:""); String formatAppendLog = stringBuffer.toString(); // appendlog - XxlJobFileAppender.appendLog(logFileName, formatAppendLog); - - logger.debug(">>>>>>>>>>> [{}]: {}", logFileName, formatAppendLog); + String logFileName = XxlJobFileAppender.contextHolder.get(); + if (logFileName!=null && logFileName.trim().length()>0) { + XxlJobFileAppender.appendLog(logFileName, formatAppendLog); + } else { + logger.info(">>>>>>>>>>> {}", formatAppendLog); + } } /** * append log with pattern * - * @ - * * @param appendLogPattern like "aaa {0} bbb {1} ccc" * @param appendLogArguments like "111, true" */ public static void log(String appendLogPattern, Object ... appendLogArguments) { - String appendLog = MessageFormat.format(appendLogPattern, appendLogArguments); - log(appendLog); + + String appendLog = appendLogPattern; + if (appendLogArguments!=null && appendLogArguments.length>0) { + appendLog = MessageFormat.format(appendLogPattern, appendLogArguments); + } + + StackTraceElement callInfo = new Throwable().getStackTrace()[1]; + logDetail(callInfo, appendLog); + } + + /** + * append exception stack + * + * @param e + */ + public static void log(Throwable e) { + + StringWriter stringWriter = new StringWriter(); + e.printStackTrace(new PrintWriter(stringWriter)); + String appendLog = stringWriter.toString(); + + StackTraceElement callInfo = new Throwable().getStackTrace()[1]; + logDetail(callInfo, appendLog); } } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/thread/JobThread.java b/xxl-job-core/src/main/java/com/xxl/job/core/thread/JobThread.java index 6084ef4b..e6d03967 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/thread/JobThread.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/thread/JobThread.java @@ -92,6 +92,14 @@ public class JobThread extends Thread{ @Override public void run() { + // init + try { + handler.init(); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + + // execute while(!toStop){ running = false; idleTimes++; @@ -106,21 +114,16 @@ public class JobThread extends Thread{ idleTimes = 0; triggerLogIdSet.remove(triggerParam.getLogId()); - // parse param - String[] handlerParams = (triggerParam.getExecutorParams()!=null && triggerParam.getExecutorParams().trim().length()>0) - ? (String[])(Arrays.asList(triggerParam.getExecutorParams().split(",")).toArray()) : null; - - - // log filename: yyyy-MM-dd/9999.log + // log filename, like "logPath/yyyy-MM-dd/9999.log" String logFileName = XxlJobFileAppender.makeLogFileName(new Date(triggerParam.getLogDateTim()), triggerParam.getLogId()); XxlJobFileAppender.contextHolder.set(logFileName); ShardingUtil.setShardingVo(new ShardingUtil.ShardingVO(triggerParam.getBroadcastIndex(), triggerParam.getBroadcastTotal())); // execute - XxlJobLogger.log("
----------- xxl-job job execute start -----------
----------- Params:" + Arrays.toString(handlerParams)); - executeResult = handler.execute(handlerParams); + XxlJobLogger.log("
----------- xxl-job job execute start -----------
----------- Param:" + triggerParam.getExecutorParams()); + executeResult = handler.execute(triggerParam.getExecutorParams()); if (executeResult == null) { - executeResult = ReturnT.FAIL; + executeResult = IJobHandler.FAIL; } XxlJobLogger.log("
----------- xxl-job job execute end(finish) -----------
----------- ReturnT:" + executeResult); @@ -165,6 +168,13 @@ public class JobThread extends Thread{ } } + // destroy + try { + handler.destroy(); + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + logger.info(">>>>>>>>>>> xxl-job JobThread stoped, hashCode:{}", Thread.currentThread()); } } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/util/JacksonUtil.java b/xxl-job-core/src/main/java/com/xxl/job/core/util/JacksonUtil.java index 086c0ce1..a679fb04 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/util/JacksonUtil.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/util/JacksonUtil.java @@ -1,11 +1,10 @@ package com.xxl.job.core.util; - -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.map.JsonMappingException; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.type.TypeReference; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java b/xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java index 95c199d2..fea47d44 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java @@ -1,11 +1,9 @@ package com.xxl.job.core.util; -import com.xxl.job.core.log.XxlJobFileAppender; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.PumpStreamHandler; -import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -27,18 +25,6 @@ public class ScriptUtil { * @throws IOException */ public static void markScriptFile(String scriptFileName, String content) throws IOException { - // filePath/ - File filePathDir = new File(XxlJobFileAppender.logPath); - if (!filePathDir.exists()) { - filePathDir.mkdirs(); - } - - // filePath/gluesource/ - File filePathSourceDir = new File(filePathDir, "gluesource"); - if (!filePathSourceDir.exists()) { - filePathSourceDir.mkdirs(); - } - // make file, filePath/gluesource/666-123456789.py FileOutputStream fileOutputStream = null; try { diff --git a/xxl-job-executor-samples/pom.xml b/xxl-job-executor-samples/pom.xml index bcbd0f13..34479551 100644 --- a/xxl-job-executor-samples/pom.xml +++ b/xxl-job-executor-samples/pom.xml @@ -14,6 +14,7 @@ xxl-job-executor-sample-spring xxl-job-executor-sample-springboot xxl-job-executor-sample-jfinal + xxl-job-executor-sample-nutz \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/pom.xml b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/pom.xml index 2e6a68ce..17444ffb 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/pom.xml +++ b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/pom.xml @@ -16,7 +16,7 @@ com.jfinal jfinal - 2.0 + 2.2 diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/config/JFinalCoreConfig.java b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/config/JFinalCoreConfig.java index aa5be69c..3b16c4af 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/config/JFinalCoreConfig.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/config/JFinalCoreConfig.java @@ -17,8 +17,9 @@ public class JFinalCoreConfig extends JFinalConfig { private Logger logger = LoggerFactory.getLogger(JFinalCoreConfig.class); // ---------------------- xxl-job executor ---------------------- - XxlJobExecutor xxlJobExecutor = null; + private XxlJobExecutor xxlJobExecutor = null; private void initXxlJobExecutor() { + // registry jobhandler XxlJobExecutor.registJobHandler("demoJobHandler", new DemoJobHandler()); XxlJobExecutor.registJobHandler("shardingJobHandler", new ShardingJobHandler()); diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/controller/IndexController.java b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/controller/IndexController.java index b00c773b..2c47b73f 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/controller/IndexController.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/controller/IndexController.java @@ -7,4 +7,5 @@ public class IndexController extends Controller { public void index(){ renderText("xxl job executor running."); } + } diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/jobhandler/DemoJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/jobhandler/DemoJobHandler.java index a33ff3c9..bf4e888d 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/jobhandler/DemoJobHandler.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/jobhandler/DemoJobHandler.java @@ -6,28 +6,27 @@ import com.xxl.job.core.log.XxlJobLogger; import java.util.concurrent.TimeUnit; - /** - * 任务Handler的一个Demo(Bean模式) + * 任务Handler示例(Bean模式) * * 开发步骤: - * 1、继承 “IJobHandler” ; - * 2、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志; - * 3、在 "JFinalCoreConfig" 中注册,执行Jobhandler名称; + * 1、继承"IJobHandler":“com.xxl.job.core.handler.IJobHandler”; + * 2、注册到执行器工厂:在 "JFinalCoreConfig.initXxlJobExecutor" 中手动注册,注解key值对应的是调度中心新建任务的JobHandler属性的值。 + * 3、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志; * * @author xuxueli 2015-12-19 19:43:36 */ public class DemoJobHandler extends IJobHandler { @Override - public ReturnT execute(String... params) throws Exception { + public ReturnT execute(String param) throws Exception { XxlJobLogger.log("XXL-JOB, Hello World."); for (int i = 0; i < 5; i++) { XxlJobLogger.log("beat at:" + i); TimeUnit.SECONDS.sleep(2); } - return ReturnT.SUCCESS; + return SUCCESS; } } diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/jobhandler/ShardingJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/jobhandler/ShardingJobHandler.java index 73bbc1df..85bd70cd 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/jobhandler/ShardingJobHandler.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/jobhandler/ShardingJobHandler.java @@ -14,7 +14,7 @@ import com.xxl.job.core.util.ShardingUtil; public class ShardingJobHandler extends IJobHandler { @Override - public ReturnT execute(String... params) throws Exception { + public ReturnT execute(String param) throws Exception { // 分片参数 ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo(); @@ -29,7 +29,7 @@ public class ShardingJobHandler extends IJobHandler { } } - return ReturnT.SUCCESS; + return SUCCESS; } } diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/resources/xxl-job-executor.properties b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/resources/xxl-job-executor.properties index 7b363dc7..4cafd293 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/resources/xxl-job-executor.properties +++ b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/resources/xxl-job-executor.properties @@ -4,10 +4,10 @@ xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin ### xxl-job executor address xxl.job.executor.appname=xxl-job-executor-sample xxl.job.executor.ip= -xxl.job.executor.port=9997 +xxl.job.executor.port=9996 ### 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= \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/webapp/WEB-INF/web.xml b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/webapp/WEB-INF/web.xml index 418f9cc3..208179ce 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/webapp/WEB-INF/web.xml +++ b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/webapp/WEB-INF/web.xml @@ -3,6 +3,7 @@ xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> + xxl-job-executor-sample-jfinal webAppRootKey @@ -23,4 +24,9 @@ /* + + + index.html + + \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/webapp/index.html b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/webapp/index.html new file mode 100644 index 00000000..7085239b --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/webapp/index.html @@ -0,0 +1 @@ +i am alive. \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/pom.xml b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/pom.xml new file mode 100644 index 00000000..56e2581c --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/pom.xml @@ -0,0 +1,38 @@ + + + + com.xuxueli + xxl-job-executor-samples + 1.9.0-SNAPSHOT + + 4.0.0 + xxl-job-executor-sample-nutz + war + + + + + org.nutz + nutz + 1.r.62 + + + + + org.slf4j + slf4j-log4j12 + ${slf4j-api.version} + + + + + com.xuxueli + xxl-job-core + ${project.parent.version} + + + + + \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/MainModule.java b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/MainModule.java new file mode 100644 index 00000000..a8163ff9 --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/MainModule.java @@ -0,0 +1,23 @@ +package com.xuxueli.executor.sample.nutz; + +import com.xuxueli.executor.sample.nutz.config.NutzSetup; +import org.nutz.mvc.annotation.*; +import org.nutz.mvc.ioc.provider.ComboIocProvider; + +/** + * nutz module + * + * @author xuxueli 2017-12-25 17:58:43 + */ +@IocBy(type = ComboIocProvider.class, + args = {"*org.nutz.ioc.loader.annotation.AnnotationIocLoader", + "com.xuxueli.executor.sample.nutz"}) +@Encoding(input = "utf-8", output = "utf-8") +@Modules(scanPackage = true) +@Localization("msg") +@Ok("json") +@Fail("json") +@SetupBy(NutzSetup.class) +public class MainModule { + +} diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/config/NutzSetup.java b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/config/NutzSetup.java new file mode 100644 index 00000000..cc7c9c24 --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/config/NutzSetup.java @@ -0,0 +1,64 @@ +package com.xuxueli.executor.sample.nutz.config; + +import com.xxl.job.core.executor.XxlJobExecutor; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.annotation.JobHandler; +import org.nutz.ioc.impl.PropertiesProxy; +import org.nutz.mvc.NutConfig; +import org.nutz.mvc.Setup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * nutz setup + * + * @author xuxueli 2017-12-25 17:58:43 + */ +public class NutzSetup implements Setup { + private Logger logger = LoggerFactory.getLogger(NutzSetup.class); + //public static final Log logger = Logs.get(); + + private XxlJobExecutor xxlJobExecutor = null; + + @Override + public void init(NutConfig cfg) { + + // regist JobHandler + String[] beanNames = cfg.getIoc().getNamesByType(IJobHandler.class); + if (beanNames==null || beanNames.length==0) { + return; + } + for (String beanName : beanNames) { + IJobHandler jobHandler = cfg.getIoc().get(IJobHandler.class, beanName); + String name = jobHandler.getClass().getAnnotation(JobHandler.class).value(); + XxlJobExecutor.registJobHandler(name, jobHandler); + } + + // load executor prop + PropertiesProxy xxlJobProp = new PropertiesProxy("xxl-job-executor.properties"); + + // init executor + xxlJobExecutor = new XxlJobExecutor(); + xxlJobExecutor.setIp(xxlJobProp.get("xxl.job.executor.ip")); + xxlJobExecutor.setPort(xxlJobProp.getInt("xxl.job.executor.port")); + xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname")); + xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses")); + xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath")); + xxlJobExecutor.setAccessToken(xxlJobProp.get("xxl.job.accessToken")); + + // start executor + try { + xxlJobExecutor.start(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + + @Override + public void destroy(NutConfig cfg) { + if (xxlJobExecutor != null) { + xxlJobExecutor.destroy(); + } + } + +} diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/jobhandler/DemoJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/jobhandler/DemoJobHandler.java new file mode 100644 index 00000000..20f1b3ba --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/jobhandler/DemoJobHandler.java @@ -0,0 +1,38 @@ +package com.xuxueli.executor.sample.nutz.jobhandler; + +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.handler.annotation.JobHandler; +import com.xxl.job.core.log.XxlJobLogger; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.util.concurrent.TimeUnit; + +/** + * 任务Handler示例(Bean模式) + * + * 开发步骤: + * 1、继承"IJobHandler":“com.xxl.job.core.handler.IJobHandler”; + * 2、注册到Nutz容器:添加“@IocBean”注解,被Nutz容器扫描为Bean实例; + * 3、注册到执行器工厂:添加“@JobHandler(value="自定义jobhandler名称")”注解,注解value值对应的是调度中心新建任务的JobHandler属性的值。 + * 4、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志; + * + * @author xuxueli 2015-12-19 19:43:36 + */ +@JobHandler(value="demoJobHandler") +@IocBean +public class DemoJobHandler extends IJobHandler { + + @Override + public ReturnT execute(String param) throws Exception { + XxlJobLogger.log("XXL-JOB, Hello World."); + + for (int i = 0; i < 5; i++) { + XxlJobLogger.log("beat at:" + i); + TimeUnit.SECONDS.sleep(2); + } + return SUCCESS; + } + +} + diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/jobhandler/ShardingJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/jobhandler/ShardingJobHandler.java new file mode 100644 index 00000000..f374731d --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/jobhandler/ShardingJobHandler.java @@ -0,0 +1,39 @@ +package com.xuxueli.executor.sample.nutz.jobhandler; + +import com.xxl.job.core.handler.annotation.JobHandler; +import org.nutz.ioc.loader.annotation.IocBean; + +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.IJobHandler; +import com.xxl.job.core.log.XxlJobLogger; +import com.xxl.job.core.util.ShardingUtil; + +/** + * 分片广播任务 + * + * @author xuxueli 2017-07-25 20:56:50 + */ +@JobHandler(value="shardingJobHandler") +@IocBean +public class ShardingJobHandler extends IJobHandler { + + @Override + public ReturnT execute(String param) throws Exception { + + // 分片参数 + ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo(); + XxlJobLogger.log("分片参数:当前分片序号 = {0}, 总分片数 = {1}", shardingVO.getIndex(), shardingVO.getTotal()); + + // 业务逻辑 + for (int i = 0; i < shardingVO.getTotal(); i++) { + if (i == shardingVO.getIndex()) { + XxlJobLogger.log("第 {0} 片, 命中分片开始处理", i); + } else { + XxlJobLogger.log("第 {0} 片, 忽略", i); + } + } + + return SUCCESS; + } + +} diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/module/IndexModule.java b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/module/IndexModule.java new file mode 100644 index 00000000..0cd0233d --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/module/IndexModule.java @@ -0,0 +1,16 @@ +package com.xuxueli.executor.sample.nutz.module; + +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +@IocBean +public class IndexModule { + + @At("/") + @Ok("json") + public String index() { + return "xxl job executor running."; + } + +} diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/resources/log4j.xml b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/resources/log4j.xml new file mode 100644 index 00000000..b9ba6cef --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/resources/log4j.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/resources/xxl-job-executor.properties b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/resources/xxl-job-executor.properties new file mode 100644 index 00000000..19be360e --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/resources/xxl-job-executor.properties @@ -0,0 +1,13 @@ +### xxl-job admin address list, such as "http://address" or "http://address01,http://address02" +xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin + +### xxl-job executor address +xxl.job.executor.appname=xxl-job-executor-sample +xxl.job.executor.ip= +xxl.job.executor.port=9997 + +### xxl-job log path +xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler + +### xxl-job, access token +xxl.job.accessToken= \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/webapp/WEB-INF/web.xml b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000..19f2817f --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,32 @@ + + + + xxl-job-executor-sample-nutz + + webAppRootKey + xxl-job-executor-sample-nutz + + + + + nutz + org.nutz.mvc.NutFilter + + modules + com.xuxueli.executor.sample.nutz.MainModule + + + + nutz + /* + + + + + index.html + + + diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/webapp/index.html b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/webapp/index.html new file mode 100644 index 00000000..7085239b --- /dev/null +++ b/xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/webapp/index.html @@ -0,0 +1 @@ +i am alive. \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java index b0fb6c01..a1a9c72d 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java @@ -10,12 +10,12 @@ import java.util.concurrent.TimeUnit; /** - * 任务Handler的一个Demo(Bean模式) + * 任务Handler示例(Bean模式) * * 开发步骤: - * 1、新建一个继承com.xxl.job.core.handler.IJobHandler的Java类; - * 2、该类被Spring容器扫描为Bean实例,如加“@Component”注解; - * 3、添加 “@JobHandler(value="自定义jobhandler名称")”注解,注解的value值为自定义的JobHandler名称,该名称对应的是调度中心新建任务的JobHandler属性的值。 + * 1、继承"IJobHandler":“com.xxl.job.core.handler.IJobHandler”; + * 2、注册到Spring容器:添加“@Component”注解,被Spring容器扫描为Bean实例; + * 3、注册到执行器工厂:添加“@JobHandler(value="自定义jobhandler名称")”注解,注解value值对应的是调度中心新建任务的JobHandler属性的值。 * 4、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志; * * @author xuxueli 2015-12-19 19:43:36 @@ -25,14 +25,14 @@ import java.util.concurrent.TimeUnit; public class DemoJobHandler extends IJobHandler { @Override - public ReturnT execute(String... params) throws Exception { + public ReturnT execute(String param) throws Exception { XxlJobLogger.log("XXL-JOB, Hello World."); for (int i = 0; i < 5; i++) { XxlJobLogger.log("beat at:" + i); TimeUnit.SECONDS.sleep(2); } - return ReturnT.SUCCESS; + return SUCCESS; } } diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/java/com/xxl/job/executor/service/jobhandler/ShardingJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/java/com/xxl/job/executor/service/jobhandler/ShardingJobHandler.java index 4c0b5c80..70578097 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/java/com/xxl/job/executor/service/jobhandler/ShardingJobHandler.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/java/com/xxl/job/executor/service/jobhandler/ShardingJobHandler.java @@ -18,7 +18,7 @@ import org.springframework.stereotype.Service; public class ShardingJobHandler extends IJobHandler { @Override - public ReturnT execute(String... params) throws Exception { + public ReturnT execute(String param) throws Exception { // 分片参数 ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo(); @@ -33,7 +33,7 @@ public class ShardingJobHandler extends IJobHandler { } } - return ReturnT.SUCCESS; + return SUCCESS; } } diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml index 9a96a4d8..e11e623d 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml @@ -3,9 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans - http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context - http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + http://www.springframework.org/schema/context/spring-context.xsd"> @@ -25,15 +25,15 @@ - + - + - + diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties index ab71b92b..d8b57728 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties @@ -7,7 +7,7 @@ xxl.job.executor.ip= xxl.job.executor.port=9999 ### 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= \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/webapp/WEB-INF/web.xml b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/webapp/WEB-INF/web.xml index 55b78eed..9179af7b 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/webapp/WEB-INF/web.xml +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/webapp/WEB-INF/web.xml @@ -3,12 +3,14 @@ xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> + xxl-job-executor-sample-spring webAppRootKey xxl-job-executor-sample-spring - + + contextConfigLocation classpath*:applicationcontext-*.xml @@ -20,7 +22,8 @@ org.springframework.web.context.ContextLoaderListener - + + index.html diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/webapp/index.html b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/webapp/index.html index ae4ee13c..7085239b 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/webapp/index.html +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/webapp/index.html @@ -1 +1 @@ -200 \ No newline at end of file +i am alive. \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/mvc/controller/IndexController.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/mvc/controller/IndexController.java index 1851d54f..37c90719 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/mvc/controller/IndexController.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/mvc/controller/IndexController.java @@ -1,18 +1,18 @@ -package com.xxl.job.executor.mvc.controller; - -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -@Controller -@EnableAutoConfiguration -public class IndexController { - - @RequestMapping("/") - @ResponseBody - String index() { - return "xxl job executor running."; - } - -} \ No newline at end of file +//package com.xxl.job.executor.mvc.controller; +// +//import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +//import org.springframework.stereotype.Controller; +//import org.springframework.web.bind.annotation.RequestMapping; +//import org.springframework.web.bind.annotation.ResponseBody; +// +//@Controller +//@EnableAutoConfiguration +//public class IndexController { +// +// @RequestMapping("/") +// @ResponseBody +// String index() { +// return "xxl job executor running."; +// } +// +//} \ No newline at end of file diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java index 5a9bce0a..1768e48e 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/DemoJobHandler.java @@ -4,35 +4,35 @@ import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.annotation.JobHandler; import com.xxl.job.core.log.XxlJobLogger; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; /** - * 任务Handler的一个Demo(Bean模式) + * 任务Handler示例(Bean模式) * * 开发步骤: - * 1、继承 “IJobHandler” ; - * 2、装配到Spring,例如加 “@Service” 注解; - * 3、加 “@JobHandler” 注解,注解value值为新增任务生成的JobKey的值;多个JobKey用逗号分割; + * 1、继承"IJobHandler":“com.xxl.job.core.handler.IJobHandler”; + * 2、注册到Spring容器:添加“@Component”注解,被Spring容器扫描为Bean实例; + * 3、注册到执行器工厂:添加“@JobHandler(value="自定义jobhandler名称")”注解,注解value值对应的是调度中心新建任务的JobHandler属性的值。 * 4、执行日志:需要通过 "XxlJobLogger.log" 打印执行日志; * * @author xuxueli 2015-12-19 19:43:36 */ @JobHandler(value="demoJobHandler") -@Service +@Component public class DemoJobHandler extends IJobHandler { @Override - public ReturnT execute(String... params) throws Exception { + public ReturnT execute(String param) throws Exception { XxlJobLogger.log("XXL-JOB, Hello World."); for (int i = 0; i < 5; i++) { XxlJobLogger.log("beat at:" + i); TimeUnit.SECONDS.sleep(2); } - return ReturnT.SUCCESS; + return SUCCESS; } } diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/ShardingJobHandler.java b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/ShardingJobHandler.java index 80cf1177..b58871fe 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/ShardingJobHandler.java +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/service/jobhandler/ShardingJobHandler.java @@ -18,7 +18,7 @@ import org.springframework.stereotype.Service; public class ShardingJobHandler extends IJobHandler { @Override - public ReturnT execute(String... params) throws Exception { + public ReturnT execute(String param) throws Exception { // 分片参数 ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo(); @@ -33,7 +33,7 @@ public class ShardingJobHandler extends IJobHandler { } } - return ReturnT.SUCCESS; + return SUCCESS; } } diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties index a12408ac..71fb98f2 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties +++ b/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties @@ -11,10 +11,10 @@ xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin ### xxl-job executor address xxl.job.executor.appname=xxl-job-executor-sample xxl.job.executor.ip= -xxl.job.executor.port=-1 +xxl.job.executor.port=9998 ### 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=