Giter Site home page Giter Site logo

elastic-job-spring-boot-starter's Introduction

elastic-job-spring-boot-starter介绍

注意点

Spring Boot 1.X版本使用elastic-job-spring-boot-starter 1.0.1版本,配置前缀为elasticJob.xxx.xxx

Spring Boot 2.X版本使用elastic-job-spring-boot-starter 1.0.2版本,配置前缀为elastic.job.xxx.xxx

Elastic-Job Spring Boot 自动集成,只需要一个注解即可发布Job。

Elastic-Job官方提供了基于Spring和Java代码2种方式的任务配置,刚开始用Elastic-Job的时候我比较喜欢用Spring XML文件的方式来配置任务。

这种方式能够很直观的看到所有的任务信息,结构比较清晰。当Spring Boot全面普及后,于是我们慢慢淡忘了XML配置。

当我发表了一篇名为《房价网是怎么使用分布式作业框架elastic-job》的文章,后面我的个人网站猿天地还推出了Elastic-Job的技术视频后,有很多人问我能不能用注解的方式来配置任务,都觉得注解比XML要简洁,方便。

由于官方没有提供Elastic-Job的Spring Boot Starter,于是我抽时间写了一个Starter,目的当然是使用注解简化XML的配置,下面我们就来看看怎么使用吧:

增加elastic-job-spring-boot-starter的Maven依赖

目前最新版本1.0.4

第一步添加仓库地址:

<repositories>
		<repository>
		    <id>jitpack.io</id>
		    <url>https://jitpack.io</url>
		</repository>
</repositories>

第二步添加依赖:

<dependency>
	    <groupId>com.github.yinjihuan</groupId>
	    <artifactId>elastic-job-spring-boot-starter</artifactId>
	    <version>1.0.5</version>
</dependency>

增加Zookeeper注册中心的配置

elastic.job.zk.serverLists=192.168.10.47:2181
elastic.job.zk.namespace=cxytiandi_job2

Zookeeper配置的前缀是elasticJob.zk,详细的属性配置请查看ZookeeperProperties

开启Elastic-Job自动配置

开启自动配置只需要在Spring Boot的启动类上增加@EnableElasticJob注解

import java.util.concurrent.CountDownLatch;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import com.cxytiandi.elasticjob.annotation.EnableElasticJob;

/**
 * ElasticJob Spring Boot集成案例
 * 
 * @author yinjihuan
 * 
 * @about http://cxytiandi.com/about
 *
 */
@SpringBootApplication
@EnableElasticJob
public class JobApplication {
	
	public static void main(String[] args) {
		new SpringApplicationBuilder().sources(JobApplication.class).web(false).run(args);
		try {
			new CountDownLatch(1).await();
		} catch (InterruptedException e) {
		}
	}
	
}

配置任务

@ElasticJobConf(name = "MySimpleJob", cron = "0/10 * * * * ?", 
	shardingItemParameters = "0=0,1=1", description = "简单任务")
public class MySimpleJob implements SimpleJob {

	public void execute(ShardingContext context) {
		System.out.println(2/0);
		String shardParamter = context.getShardingParameter();
		System.out.println("分片参数:"+shardParamter);
		int value = Integer.parseInt(shardParamter);
		for (int i = 0; i < 1000000; i++) {
			if (i % 2 == value) {
				String time = new SimpleDateFormat("HH:mm:ss").format(new Date());
				System.out.println(time + ":开始执行简单任务" + i);
			}
		}
	}

}

任务的配置只需要在任务类上增加一个ElasticJobConf注解,注解中有很多属性,这些属性都是任务的配置,详细的属性配置请查看ElasticJobConf

到此为止,我们就快速的使用注解发布了一个任务,DataflowJob和ScriptJob的使用方式一样。

使用示列参考:elastic-job-spring-boot-example

事件追踪功能使用

事件追踪功能在注解中也只需要配置eventTraceRdbDataSource=你的数据源 就可以使用了,数据源用什么连接池无限制,唯一需要注意的一点是你的数据源必须在spring-boot-elastic-job-starter之前创建,因为spring-boot-elastic-job-starter中依赖了你的数据源,下面我以druid作为连接池来进行讲解。

引入druid的Spring Boot Starter,GitHub地址:druid-spring-boot-starter

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid-spring-boot-starter</artifactId>
	<version>1.1.2</version>
</dependency>

配置连接池属性:

spring.datasource.druid.log.url=jdbc:mysql://localhost:3306/event_log
spring.datasource.druid.log.username=root
spring.datasource.druid.log.password=123456
spring.datasource.druid.log.driver-class-name=com.mysql.jdbc.Driver

然后在项目中定义一个配置类,配置连接池,手动配置的原因是连接池可以在elastic-job-starter之前被初始化。

@Configuration
public class BeanConfig {
	
	/**
	 * 任务执行事件数据源
	 * @return
	 */
	@Bean("datasource")
	@ConfigurationProperties("spring.datasource.druid.log")
	public DataSource dataSourceTwo(){
	    return DruidDataSourceBuilder.create().build();
	}
	
}

然后在注解中增加数据源的配置即可:

@ElasticJobConf(name = "MySimpleJob", cron = "0/10 * * * * ?", 
	shardingItemParameters = "0=0,1=1", description = "简单任务", eventTraceRdbDataSource = "datasource")

application.properties中配置任务信息

使用注解是比较方便,但很多时候我们需要不同的环境使用不同的配置,测试环境跟生产环境的配置肯定是不一样的,当然你也可以在发布之前将注解中的配置调整好然后发布。

为了能够让任务的配置区分环境,还可以在属性文件中配置任务的信息,当属性文件中配置了任务的信息,优先级就比注解中的高。

首先还是在任务类上加@ElasticJobConf(name = "MySimpleJob")注解,只需要增加一个name即可,任务名是唯一的。

剩下的配置都可以在属性文件中进行配置,格式为elasticJob.任务名.配置属性=属性值

elastic.job.MySimpleJob.cron=0/10 * * * * ?
elastic.job.MySimpleJob.overwrite=true
elastic.job.MySimpleJob.shardingTotalCount=1
elastic.job.MySimpleJob.shardingItemParameters=0=0,1=1
elastic.job.MySimpleJob.jobParameter=test
elastic.job.MySimpleJob.failover=true
elastic.job.MySimpleJob.misfire=true
elastic.job.MySimpleJob.description=simple job
elastic.job.MySimpleJob.monitorExecution=false
elastic.job.MySimpleJob.listener=com.cxytiandi.job.core.MessageElasticJobListener
elastic.job.MySimpleJob.jobExceptionHandler=com.cxytiandi.job.core.CustomJobExceptionHandler
elastic.job.MySimpleJob.disabled=true

Script任务使用说明

由于Script任务的执行逻辑是在具体的脚本中,是通过scriptCommandLine来指定执行脚本的路径。我这边为了统一的去发现项目中的任务列表,还是需要建一个脚本的Java类,加上ElasticJobConf注解,只是不需要写逻辑而已,示例如下:

/**
 * 脚本任务不需要写逻辑,逻辑在被执行的脚本中,这边只是定义一个任务而已
 * @author yinjihuan
 *
 */
@ElasticJobConf(name = "MyScriptJob")
public class MyScriptJob implements ScriptJob {

	public void execute(ShardingContext context) {
		
	}

}

配置:

elastic.job.MyScriptJob.cron=0/10 * * * * ?
elastic.job.MyScriptJob.overwrite=true
elastic.job.MyScriptJob.scriptCommandLine=D:\\apache-tomcat-addrepo-allcity\\bin\\startup.bat

 Spring XML配置代码示例

https://github.com/yinjihuan/spring-cloud/tree/master/fangjia-job

作者

欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)

PS:目前星球中正在星主的带领下组队学习Sentinel,等你哦!

微信扫码加入猿天地知识星球

猿天地

elastic-job-spring-boot-starter's People

Contributors

colinzou avatar longfeizheng avatar yinjihuan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elastic-job-spring-boot-starter's Issues

动态配置job failover不生效

动态添加job(配置了failover=true monitorExecution=true),生成的zookeeper节点上没有失效转移的目录,本地单机调试:手动杀死进程后再重启,就没有继续进行该动态job任务了。而内置的MySimpleJob可以继续进行。
下图是我的动态添加参数和zookeeper节点信息,请问是参数配置错了嘛?
image
image

application.yml中配置任务信息,应用起不来

application.yml中配置任务信息,应用起不来,配置如下

elastic:
job:
job1:
cron: * 0/5 * * * ?
description: 任务1
disabled: false
failover: true
jobParameter: 1800000,300000
misfire: false
monitorExecution: false
overwrite: true
shardingItemParameters: 0=0,1=1
shardingTotalCount: 1

不支持spring-boot2.0+

2.0以上版本不支持驼峰参数,需要修改为"-"方式

@ConfigurationProperties(prefix = "elasticJob.zk")
public class ZookeeperProperties {}
可以修改为
@ConfigurationProperties(prefix = "elastic-job.zk")

@component
@configuration
public class JobConfParser implements ApplicationContextAware {
private String prefix = "elasticJob.";
}
可以修改为:
@component
@configuration
public class JobConfParser implements ApplicationContextAware {
private String prefix = "elastic-job.";
}

初始化错误

Failed to instantiate [com.dangdang.ddframe.job.lite.spring.api.SpringJobScheduler] 配置OK的

动态添加任务的bug

类JobController动态添加SCRIPT任务54行if ("ScriptJob".equals(job.getJobType())) {},应该修改为if ("ScriptJob".equals(job.getJobType())) {}

提个需求

首先非常感谢你这个项目,,但是我们有这样一个需求,就是 开发环境下面 不想用elasticsearch ,测试环境才用,这个时候自然想到了用profile ,但是这里有个问题就是,只要我pom 引用了你的项目,那么就会自动先去连zookeeper 如果没有启动的话,就报错了。然后springboot就退出。所以是否能支持我在真正操作的时候才去看zookeeper 是否连接上,,或者是我用了 指定的profile才生效。。

运行示例程序elastic-job-spring-boot-example报错java.lang.IllegalStateException

您好,我下载elastic-job-spring-boot-example后,只保留MySimpleJob任务相关配置,报错java.lang.IllegalStateException,详细报错如下:

2018-04-20 12:34:00.967 ERROR 2120 --- [ain-EventThread] o.a.c.framework.recipes.cache.TreeCache :

java.lang.IllegalStateException: instance must be started before calling this method
at com.google.common.base.Preconditions.checkState(Preconditions.java:173) ~[guava-18.0.jar:na]
at org.apache.curator.framework.imps.CuratorFrameworkImpl.getChildren(CuratorFrameworkImpl.java:391) ~[curator-framework-2.10.0.jar:na]
at org.apache.curator.framework.recipes.cache.TreeCache$TreeNode.doRefreshChildren(TreeCache.java:263) ~[curator-recipes-2.10.0.jar:na]
at org.apache.curator.framework.recipes.cache.TreeCache$TreeNode.refreshChildren(TreeCache.java:251) ~[curator-recipes-2.10.0.jar:na]
at org.apache.curator.framework.recipes.cache.TreeCache$TreeNode.process(TreeCache.java:351) ~[curator-recipes-2.10.0.jar:na]
at org.apache.curator.framework.imps.NamespaceWatcher.process(NamespaceWatcher.java:62) [curator-framework-2.10.0.jar:na]
at org.apache.zookeeper.ClientCnxn$EventThread.processEvent(ClientCnxn.java:522) [zookeeper-3.4.6.jar:3.4.6-1569965]
at org.apache.zookeeper.ClientCnxn$EventThread.run(ClientCnxn.java:498) [zookeeper-3.4.6.jar:3.4.6-1569965]

2018-04-20 12:34:00.967 INFO 2120 --- [ain-EventThread] org.apache.zookeeper.ClientCnxn : EventThread shut down
2018-04-20 12:34:00.967 ERROR 2120 --- [tor-TreeCache-1] o.a.c.framework.recipes.cache.TreeCache :

com.dangdang.ddframe.job.reg.exception.RegException: java.lang.IllegalStateException: instance must be started before calling this method
at com.dangdang.ddframe.job.reg.exception.RegExceptionHandler.handleException(RegExceptionHandler.java:52) ~[elastic-job-common-core-2.1.5.jar:na]
at com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter.getDirectly(ZookeeperRegistryCenter.java:162) ~[elastic-job-common-core-2.1.5.jar:na]
at com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter.get(ZookeeperRegistryCenter.java:137) ~[elastic-job-common-core-2.1.5.jar:na]
at com.dangdang.ddframe.job.lite.internal.storage.JobNodeStorage.getJobNodeData(JobNodeStorage.java:72) ~[elastic-job-lite-core-2.1.5.jar:na]
at com.dangdang.ddframe.job.lite.internal.config.ConfigurationService.load(ConfigurationService.java:54) ~[elastic-job-lite-core-2.1.5.jar:na]
at com.dangdang.ddframe.job.lite.internal.failover.FailoverListenerManager.isFailoverEnabled(FailoverListenerManager.java:70) ~[elastic-job-lite-core-2.1.5.jar:na]
at com.dangdang.ddframe.job.lite.internal.failover.FailoverListenerManager.access$000(FailoverListenerManager.java:39) ~[elastic-job-lite-core-2.1.5.jar:na]
at com.dangdang.ddframe.job.lite.internal.failover.FailoverListenerManager$JobCrashedJobListener.dataChanged(FailoverListenerManager.java:78) ~[elastic-job-lite-core-2.1.5.jar:na]
at com.dangdang.ddframe.job.lite.internal.listener.AbstractJobListener.childEvent(AbstractJobListener.java:44) ~[elastic-job-lite-core-2.1.5.jar:na]
at org.apache.curator.framework.recipes.cache.TreeCache$2.apply(TreeCache.java:732) [curator-recipes-2.10.0.jar:na]
at org.apache.curator.framework.recipes.cache.TreeCache$2.apply(TreeCache.java:726) [curator-recipes-2.10.0.jar:na]
at org.apache.curator.framework.listen.ListenerContainer$1.run(ListenerContainer.java:93) [curator-framework-2.10.0.jar:na]
at com.google.common.util.concurrent.MoreExecutors$DirectExecutorService.execute(MoreExecutors.java:299) [guava-18.0.jar:na]
at org.apache.curator.framework.listen.ListenerContainer.forEach(ListenerContainer.java:85) [curator-framework-2.10.0.jar:na]
at org.apache.curator.framework.recipes.cache.TreeCache.callListeners(TreeCache.java:725) [curator-recipes-2.10.0.jar:na]
at org.apache.curator.framework.recipes.cache.TreeCache.access$1400(TreeCache.java:71) [curator-recipes-2.10.0.jar:na]
at org.apache.curator.framework.recipes.cache.TreeCache$4.run(TreeCache.java:843) [curator-recipes-2.10.0.jar:na]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_144]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_144]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_144]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_144]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: java.lang.IllegalStateException: instance must be started before calling this method
at com.google.common.base.Preconditions.checkState(Preconditions.java:173) ~[guava-18.0.jar:na]
at org.apache.curator.framework.imps.CuratorFrameworkImpl.getData(CuratorFrameworkImpl.java:375) ~[curator-framework-2.10.0.jar:na]
at com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter.getDirectly(ZookeeperRegistryCenter.java:158) ~[elastic-job-common-core-2.1.5.jar:na]
... 22 common frames omitted

动态job手动触发时会重复执行的bug

在测试过程中,出现了定时执行正常,但手动触发执行会执行2次job的情况,经过debug发现JobService中应该是重复执行了springJobScheduler的init方法所致,但不明白为什么定时是不执行2次,解决方法是去掉JobService类中addJob方法中最后的springJobScheduler.init();就正常了,不知道作者遇到过没?

A bean with that name has already been defined in null and overriding is disabled.

你好,我遇到一个问题,报错信息如下

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'SpringJobScheduler', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

按错误信息提示,配置一下spring.main.allow-bean-definition-overriding=true就可以了。我是注解与 properties 两种形式混用的,不同的 JOB。而且 job name 也没有重复,不知为何出现这个报错

JobConfParser解析注解ElasticJobConf优化

#1问题描述
JobConfParser 实现了 ApplicationContextAware接口,spring启动的时候会调用setApplicationContext方法,在该方法里完成对注解ElasticJobConf解析,同时注册任务,假如系统应用中额外定义Aware标注接口,自定义BeanPostProcessor处理器发现实现了ApplicationContextAware就注入ApplicationContext,那么会导致setApplicationContext方法重复调用,任务重复注册。

建议修复改造一下就行。

监听任务节点创建逻辑的疑问

com.xiaoju.automarket.elasticjobstarter.dynamic.service.JobService#monitorJobRegister
方法的实现里面有一行获取监听到节点的配置。
String config = new String((byte[])client.getData().forPath(data.getPath() + "/config"));
这一行直接去读取config节点。
看了下jobx的源码里面新任务注册的逻辑。

com.xiaoju.automarket.elastic.job.lite.internal.config.ConfigurationService#persist
com.xiaoju.automarket.elastic.job.lite.internal.storage.JobNodeStorage#replaceJobNode
com.xiaoju.automarket.elastic.job.reg.base.RegistryCenter#persist
client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(key, value.getBytes(Charsets.UTF_8));

创建/xxx/MyJob/config节点之前,会先创建/xxx/MyJob节点。
在极端情况下,/xxx/MyJob创建之后,/xxx/MyJob/config节点创建之前,监听逻辑读取config节点报错。
org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /xxx/MyJob/config

curator里面的创建任务节点相关代码见
org.apache.curator.framework.imps.CreateBuilderImpl#pathInForeground
会根据org.apache.curator.framework.imps.CreateBuilderImpl#createParentsIfNeeded判断是否创建父节点,如果该值为true,会先创建父节点,再创建子节点。

转发+EnableElasticJob的修改建议

感谢楼主的代码,拿来用了!!!
看了一下代码,注解@EnableElasticJob,最终通过import引入了JobParserAutoConfiguration,其实在spring.factories中也配置自动装配:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.cxytiandi.elasticjob.autoconfigure.JobParserAutoConfiguration
这样@EnableElasticJob注解的含义就没有体现出来。
个人理解@EnableElasticJob目的是当检测到系统启动类上有EnableElasticJob时,才启动自动转配,所以,可以修改EnableElasticJob和JobParserAutoConfiguration的定义:
@retention(RetentionPolicy.RUNTIME)
@documented
@inherited
public @interface EnableElasticJob{}

@configuration
@ConditionalOnBean(annotation = EnableElasticJob.class)
public class JobParserAutoConfiguration {}

jobService.addJob通过获取ZK信息注册任务的例外场景

#1、问题
现有代码是通过判断计数器JOB_ADD_COUNT是否为1来决定是否执行addJob(job)方法,但是这样还是有例外场景。
#2、场景
比如有进程A,B,都需要执行同样的任务,先启动进程A,显示调用了addJob方法,此时在zk上完成任务的注册。待注册成功后启动进程B,没有显示调用addJob,那么monitorJobRegister方法启动监听,执行
case CHILD_ADDED的逻辑,但是在进程B中由于还没有执行对应job的addJob方法,此时的计数器还没有初始化,那么monitorJobRegister中的的动态注册任务是不会执行的。

#3、分析
正常情况下,进程启动后,由进程解析ElasticJobConf,然后注册任务(addJob),那么原有的逻辑是不会有问题的,但是存在一种例外情况,如上所述,启动进程B,在上下文中没有ElasticJobConf注解,纯碎是根据zk的注册信息,通过执行monitorJobRegister监听代码,完成任务的注册。

建议,可以综合考虑上述的两种情况,在JobService中维护一个任务注册器,只要任务已经注册了,就不调用addJob方法,否则就执行。

提两个问题

您好,使用中发现的小问题

1 代码位置: ElasticJobConf conf = (ElasticJobConf)clz.getAnnotation(ElasticJobConf.class);
使用cglib的时候直接是代理类,就取不到 这个注解

2 代码位置: String jobTypeName = clzz.getInterfaces()[0].getSimpleName();
如果任务类抽出一层父类,父类实现任务接口,子类继承父类,就无法直接取到获取到 interfaces 了

springboot 1.5.10 启动两个实例后报错

A,B两个实例 ,A实例启动后正常执行任务,随后B实例启动报错,A实例报错如下:
java.lang.IllegalStateException: instance must be started before calling this method
2020-10-09 18:28:20.917 ERROR 1388 --- [tor-TreeCache-0] o.a.c.framework.recipes.cache.TreeCache :

com.dangdang.ddframe.job.reg.exception.RegException: java.lang.IllegalStateException: instance must be started before calling this method
at com.dangdang.ddframe.job.reg.exception.RegExceptionHandler.handleException(RegExceptionHandler.java:52)
at com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter.getDirectly(ZookeeperRegistryCenter.java:162)
at com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter.get(ZookeeperRegistryCenter.java:143)
at com.dangdang.ddframe.job.lite.internal.storage.JobNodeStorage.getJobNodeData(JobNodeStorage.java:72)
at com.dangdang.ddframe.job.lite.internal.config.ConfigurationService.load(ConfigurationService.java:54)
at com.dangdang.ddframe.job.lite.internal.failover.FailoverListenerManager.isFailoverEnabled(FailoverListenerManager.java:70)
at com.dangdang.ddframe.job.lite.internal.failover.FailoverListenerManager.access$000(FailoverListenerManager.java:39)
at com.dangdang.ddframe.job.lite.internal.failover.FailoverListenerManager$JobCrashedJobListener.dataChanged(FailoverListenerManager.java:78)
at com.dangdang.ddframe.job.lite.internal.listener.AbstractJobListener.childEvent(AbstractJobListener.java:44)
at org.apache.curator.framework.recipes.cache.TreeCache$2.apply(TreeCache.java:732)
at org.apache.curator.framework.recipes.cache.TreeCache$2.apply(TreeCache.java:726)
at org.apache.curator.framework.listen.ListenerContainer$1.run(ListenerContainer.java:93)
at com.google.common.util.concurrent.MoreExecutors$DirectExecutorService.execute(MoreExecutors.java:296)
at org.apache.curator.framework.listen.ListenerContainer.forEach(ListenerContainer.java:85)
at org.apache.curator.framework.recipes.cache.TreeCache.callListeners(TreeCache.java:725)
at org.apache.curator.framework.recipes.cache.TreeCache.access$1400(TreeCache.java:71)
at org.apache.curator.framework.recipes.cache.TreeCache$4.run(TreeCache.java:843)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: instance must be started before calling this method
at com.google.common.base.Preconditions.checkState(Preconditions.java:444)
at org.apache.curator.framework.imps.CuratorFrameworkImpl.getData(CuratorFrameworkImpl.java:375)
at com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter.getDirectly(ZookeeperRegistryCenter.java:158)
... 22 common frames omitted
B实例报错如下:
java.lang.NullPointerException: null
at com.dangdang.ddframe.job.lite.internal.failover.FailoverListenerManager$JobCrashedJobListener.dataChanged(FailoverListenerManager.java:80)
at com.dangdang.ddframe.job.lite.internal.listener.AbstractJobListener.childEvent(AbstractJobListener.java:44)
at org.apache.curator.framework.recipes.cache.TreeCache$2.apply(TreeCache.java:732)
at org.apache.curator.framework.recipes.cache.TreeCache$2.apply(TreeCache.java:726)
at org.apache.curator.framework.listen.ListenerContainer$1.run(ListenerContainer.java:93)
at com.google.common.util.concurrent.MoreExecutors$DirectExecutorService.execute(MoreExecutors.java:296)
at org.apache.curator.framework.listen.ListenerContainer.forEach(ListenerContainer.java:85)
at org.apache.curator.framework.recipes.cache.TreeCache.callListeners(TreeCache.java:725)
at org.apache.curator.framework.recipes.cache.TreeCache.access$1400(TreeCache.java:71)
at org.apache.curator.framework.recipes.cache.TreeCache$4.run(TreeCache.java:843)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobConfParser' defined in com.cxytiandi.elasticjob.autoconfigure.JobParserAutoConfiguration: Initialization of bean failed; nested exception is com.dangdang.ddframe.job.exception.JobSystemException: org.quartz.SchedulerException: The Scheduler has been shutdown.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134)
at ai.shanshu.shuhaisc.ShuhaiscFrApplication.main(ShuhaiscFrApplication.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: com.dangdang.ddframe.job.exception.JobSystemException: org.quartz.SchedulerException: The Scheduler has been shutdown.
at com.dangdang.ddframe.job.lite.internal.schedule.JobScheduleController.scheduleJob(JobScheduleController.java:57)
at com.dangdang.ddframe.job.lite.api.JobScheduler.init(JobScheduler.java:111)
at com.cxytiandi.elasticjob.parser.JobConfParser.setApplicationContext(JobConfParser.java:154)
at org.springframework.context.support.ApplicationContextAwareProcessor.invokeAwareInterfaces(ApplicationContextAwareProcessor.java:121)
at org.springframework.context.support.ApplicationContextAwareProcessor.postProcessBeforeInitialization(ApplicationContextAwareProcessor.java:97)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
... 19 common frames omitted
Caused by: org.quartz.SchedulerException: The Scheduler has been shutdown.
at org.quartz.core.QuartzScheduler.validateState(QuartzScheduler.java:795)
at org.quartz.core.QuartzScheduler.checkExists(QuartzScheduler.java:1542)
at org.quartz.impl.StdScheduler.checkExists(StdScheduler.java:564)
at com.dangdang.ddframe.job.lite.internal.schedule.JobScheduleController.scheduleJob(JobScheduleController.java:52)
... 26 common frames omitted

JobService的monitorJobRegister加了个小改动

当把jo类删掉掉,启动找不到job导致启动失败,在case CHILD_ADDED里加了下面的改动:
if (ClassUtils.isPresent(job.getJobClass(), JobService.class.getClassLoader())) {
addJob(job);
} else {
removeJob(job.getJobName());
}

distributedListener监听出现交替多次执行现象,而非主节点执行

注解@ElasticJobConf,有个属性“distributedListener”,现在继承AbstractDistributeOnceElasticJobListener类,想在所有分片执行前执行某个操作(即重写方法doBeforeJobExecutedAtLastStarted),发现在控制台进行调用,这个方法持交替性的执行多次,而非单个主节点执行(如:第一次执行了,doBeforeJobExecutedAtLastStarted执行一次,第二次执行了,doBeforeJobExecutedAtLastStarted执行两次,之后交替重复执行 。此现象测试来源于10台机器,分20片得到的结果)

不知道这个情况,其它小伙伴们遇到没有?

作业类型jobType值不一致

JobController.addJob方法中,if ("ScriptJob".equals(job.getJobType())) {} 中的常量"ScriptJob"是不是应该改为“SCRIPT”?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.