ElasticJob 3.0.0-alpha 自定义JobErrorHandler
起因
leader 要求任务调度得实现故障转移和错误重试。
令人尴尬的是,elasticJob只有失效转移,并没有错误重试。
不过xxljob可以进行失败错误:
这就真的很尴尬了 : )
有个解决方案,可以利用spring的重试机制,点这里查看详情。
但我这倔脾气起来了,我特么就是不想引用包,就不能解决了??
然后就有了这篇文章,泪目,泪目!!!
正文
ElasticJobConfigurationProperties
先去属性配置类里面康康:
@Getter
@Setter
public class ElasticJobConfigurationProperties {
private Class<? extends ElasticJob> elasticJobClass;
private String elasticJobType;
private String cron;
private String jobBootstrapBeanName;
private int shardingTotalCount;
private String shardingItemParameters;
private String jobParameter;
private boolean monitorExecution;
private boolean failover;
private boolean misfire;
private int maxTimeDiffSeconds = -1;
private int reconcileIntervalMinutes;
private String jobShardingStrategyType;
private String jobExecutorServiceHandlerType;
private String jobErrorHandlerType;
private String description;
private Properties props = new Properties();
private boolean disabled;
private boolean overwrite;
public JobConfiguration toJobConfiguration(final String jobName) {......}
}
然后,你会惊讶的发现,真的很官网上说的一样,关于错误重试的字眼一点点都没有
柳暗花明又一村,可能是被上帝摸了摸头。在elasticJob的common包下,看见了异常处理handle的实现。
心跳有点止不住。。。。。。
随后在属性配置类中,找到了jobErrorHandlerType属性
内心的戏好像已经停不下来了。。。。。
思路:通过自定义JobErrorHandler,来达到错误重试效果
RetryJobErrorHandler
@Component
@Slf4j
public class RetryJobErrorHandler implements JobErrorHandler {
private ElasticJobExecutor jobExecutor;
private static int RETRY_TIME = 3;
@Override
public void handleException(String jobName, Throwable cause) {
log.error(String.format("Job '%s' exception occur in job processing, start retry {}", jobName, RETRY_TIME), cause);
if (RETRY_TIME == 0) {
log.error(String.format("Job '%s' exception occur in job processing, retry still failure", jobName), cause);
return;
}
jobExecutor.execute();
RETRY_TIME--;
}
@Override
public String getType() {
return "Retry";
}
}
simpleJob-user:
elasticJobClass: io.will.ejob.job.UserSimpleJob
cron: 0/10 * * * * ?
shardingTotalCount: 3
overwrite: true
jobErrorHandlerType: io.will.ejob.retry.RetryJobErrorHandler
写完自定义类,并在yaml中配置好类路径,已经止不住笑起来了
跑起来先:
Caused by: org.apache.shardingsphere.elasticjob.infra.exception.JobConfigurationException: Can not find job error handler type 'io.will.ejob.retry.RetryJobErrorHandler'.
at org.apache.shardingsphere.elasticjob.infra.handler.error.JobErrorHandlerFactory.getHandler(JobErrorHandlerFactory.java:56) ~[elasticjob-infra-common-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.executor.ElasticJobExecutor.<init>(ElasticJobExecutor.java:76) ~[elasticjob-executor-kernel-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.executor.ElasticJobExecutor.<init>(ElasticJobExecutor.java:63) ~[elasticjob-executor-kernel-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.lite.internal.schedule.JobScheduler.<init>(JobScheduler.java:86) ~[elasticjob-lite-core-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.lite.api.bootstrap.impl.ScheduleJobBootstrap.<init>(ScheduleJobBootstrap.java:43) ~[elasticjob-lite-core-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.lite.spring.boot.job.ElasticJobLiteAutoConfiguration.registerClassedJob(ElasticJobLiteAutoConfiguration.java:114) ~[elasticjob-lite-spring-boot-starter-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.lite.spring.boot.job.ElasticJobLiteAutoConfiguration.constructJobBootstraps(ElasticJobLiteAutoConfiguration.java:97) ~[elasticjob-lite-spring-boot-starter-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.lite.spring.boot.job.ElasticJobLiteAutoConfiguration.createJobBootstrapBeans(ElasticJobLiteAutoConfiguration.java:70) ~[elasticjob-lite-spring-boot-starter-3.0.0-alpha.jar:3.0.0-alpha]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]
... 19 common frames omitted
我还是太年轻!!!
找问题
怎么会找不到呐,没有理由找不到啊,放容器里面了的啊
对比了下yaml配置类里的 elasticJobClass 和 jobErrorHandlerType
嗯??? class??type??莫非不是写类路径??
再进入ElasticJobConfigurationProperties 类中康康:
......
private Class<? extends ElasticJob> elasticJobClass;
......
private String jobErrorHandlerType;
......
是咯!!!一个是类,一个是String,肯定找不到
simpleJob-user:
elasticJobClass: io.will.ejob.job.UserSimpleJob
cron: 0/10 * * * * ?
shardingTotalCount: 3
overwrite: true
jobErrorHandlerType: Retry
好像看见了胜利的手,再向我招来!!!
Caused by: org.apache.shardingsphere.elasticjob.infra.exception.JobConfigurationException: Can not find job error handler type 'Retry'.
at org.apache.shardingsphere.elasticjob.infra.handler.error.JobErrorHandlerFactory.getHandler(JobErrorHandlerFactory.java:56) ~[elasticjob-infra-common-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.executor.ElasticJobExecutor.<init>(ElasticJobExecutor.java:76) ~[elasticjob-executor-kernel-3.0.0-alpha.jar:3.0.0-alpha]
at org.apache.shardingsphere.elasticjob.executor.ElasticJobExecutor.<init>(ElasticJobExecutor.java:63) ~
......
傻眼了!!!还是不可以!!!
Debug
事到如今,也只剩下Debug,进去康康到底发生了什么。。。泪目!!!
嗯嗯能够拿到Type,再进去康康
找到原因了:是在类加载时候,自定义JobErrorHandler走远了
我好像有点肝不动了 !!!
解决方法
- 反射
直接上代码:
static {
try {
HashMap<String, JobErrorHandler> stringJobErrorHandlerHashMap = new LinkedHashMap<>();
RetryJobErrorHandler retryJobErrorHandler = new RetryJobErrorHandler();
stringJobErrorHandlerHashMap.put("Retry", retryJobErrorHandler);
Class<?> factoryClass = Class.forName("org.apache.shardingsphere.elasticjob.infra.handler.error.JobErrorHandlerFactory");
Field[] fields = factoryClass.getDeclaredFields();
Field handlers = null;
for (int i = 0; i < fields.length; i ++) {
fields[i].setAccessible(true);
System.out.println(fields[i].getName());
if (fields[i].getName().equals("HANDLERS")) {
handlers = fields[i];
}
}
int modify = handlers.getModifiers();
handlers.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
// 修改权限
modify = handlers.getModifiers() & ~Modifier.FINAL;
//更改目标对象的修饰符
modifiersField.setInt(handlers, modify);
handlers.set(null, stringJobErrorHandlerHashMap);
System.out.println(handlers);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
看截图:
- Java configuration
人家大佬是这么说的:
使用配置类:
// 待更新