I started quartz server instance using spring (as in article), it works good. But when I try to start another app with quartz client and connect to quartz server, I have an error, please help what I'm doing wrong.
Server config:
@Configuration
public class ServerConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean(ApplicationContext applicationContext) {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
schedulerFactory.setSchedulerListeners(...);
schedulerFactory.setJobFactory(...);
schedulerFactory.setTriggers(...);
return schedulerFactory;
}
...
}
Client config:
@Configuration
public class ClientConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
return schedulerFactory;
}
...
}
Server quartz.properties:
org.quartz.scheduler.instanceName=myScheduler
org.quartz.scheduler.rmi.export=true
org.quartz.scheduler.rmi.createRegistry=true
org.quartz.scheduler.rmi.registryHost=localhost
org.quartz.scheduler.rmi.registryPort=1099
org.quartz.scheduler.rmi.serverPort=1100
Client quartz.properties:
org.quartz.scheduler.instanceName=myScheduler
org.quartz.scheduler.rmi.proxy=true
org.quartz.scheduler.rmi.registryHost=localhost
org.quartz.scheduler.rmi.registryPort=1099
Server logs:
[2019-09-03] [10:07:26.171] INFO SchedulerFactoryBean:538 - Loading Quartz config from [class path resource [quartz.properties]]
[2019-09-03] [10:07:26.229] INFO StdSchedulerFactory:1208 - Using default implementation for ThreadExecutor
[2019-09-03] [10:07:26.272] INFO SchedulerSignalerImpl:61 - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
[2019-09-03] [10:07:26.273] INFO QuartzScheduler:229 - Quartz Scheduler v.2.3.0 created.
[2019-09-03] [10:07:26.277] INFO RAMJobStore:155 - RAMJobStore initialized.
[2019-09-03] [10:07:26.338] INFO QuartzScheduler:421 - Scheduler bound to RMI registry under name 'schedulerFactoryBean_$_NON_CLUSTERED'
[2019-09-03] [10:07:26.343] INFO QuartzScheduler:294 - Scheduler meta-data: Quartz Scheduler (v2.3.0) 'schedulerFactoryBean' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - access via RMI.
...
[2019-09-03] [10:07:26.344] INFO StdSchedulerFactory:1362 - Quartz scheduler 'schedulerFactoryBean' initialized from an externally provided properties instance.
[2019-09-03] [10:07:26.345] INFO StdSchedulerFactory:1366 - Quartz scheduler version: 2.3.0
...
[2019-09-03] [10:07:29.12] INFO SchedulerFactoryBean:684 - Starting Quartz Scheduler now
[2019-09-03] [10:07:29.13] INFO QuartzScheduler:547 - Scheduler schedulerFactoryBean_$_NON_CLUSTERED started.
Client logs:
[2019-09-03] [10:11:53.255] INFO SchedulerFactoryBean:538 - Loading Quartz config from [class path resource [quartz.properties]]
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'schedulerFactoryBean' defined in class path resource [com/mypackage/ClientConfig.class]: Invocation of init method failed; nested exception is org.quartz.SchedulerException: Operation not supported for remote schedulers.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1631)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:742)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:73)
... 3 more
Caused by: org.quartz.SchedulerException: Operation not supported for remote schedulers.
at org.quartz.impl.RemoteScheduler.getListenerManager(RemoteScheduler.java:913)
at org.springframework.scheduling.quartz.SchedulerAccessor.registerListeners(SchedulerAccessor.java:340)
at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:476)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1689)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1627)
... 13 more
As you can see, the error is:
org.quartz.SchedulerException: Operation not supported for remote schedulers.
and happens while bean initialization. What's wrong with it?
After client fails to start, server shows in logs:
[2019-09-03] [10:11:53.462] INFO QuartzScheduler:666 - Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutting down.
[2019-09-03] [10:11:53.462] INFO QuartzScheduler:585 - Scheduler schedulerFactoryBean_$_NON_CLUSTERED paused.
[2019-09-03] [10:11:53.871] INFO QuartzScheduler:447 - Scheduler un-bound from name 'schedulerFactoryBean_$_NON_CLUSTERED' in RMI registry
[2019-09-03] [10:11:53.872] INFO QuartzScheduler:740 - Scheduler schedulerFactoryBean_$_NON_CLUSTERED shutdown complete.
I have versions of Spring - 4.3.20, Quartz - 2.3.0
Update:
I see registerListeners()
call in SchedulerFactoryBean
:
@Override
public void afterPropertiesSet() throws Exception {
...
try {
registerListeners();
registerJobsAndTriggers();
}
catch (Exception ex) {
try {
this.scheduler.shutdown(true);
}
catch (Exception ex2) {
logger.debug("Scheduler shutdown exception after registration failure", ex2);
}
throw ex;
}
}
and in registerListeners()
we call getScheduler().getListenerManager()
which fails with Operation not supported for remote schedulers
exception. How to avoid calling registerListeners()
for RemoteScheduler?
Finally I get it working the following way:
I refused from using Spring's SchedulerFactoryBean
on a client, but instead I directly create an instance of StdSchedulerFactory
from quartz library (then it properly creates an instance of RemoteScheduler
): new StdSchedulerFactory()
. It properly connects to a server quartz instance.
Due to I cannot obtain an instance of StdSchedulerFactory
from SchedulerFactoryBean
I just pass both to beans where it is needed. So on a client app SchedulerFactoryBean
is null, and on a server app StdSchedulerFactory
is null.
Job schedule part is the same for both factories as all I do with them is obtain scheduler:
private Scheduler getScheduler() throws SchedulerException {
if (schedulerFactoryBean != null) return schedulerFactoryBean.getScheduler();
if (schedulerFactory != null) return schedulerFactory.getScheduler();
else return null;
}
and then...
Scheduler scheduler = getScheduler();
if (scheduler != null) {
scheduler.scheduleJob(job, trigger);
}