Quartz doesn't work properly in cluster environment

i am using quartz-2.2.3 on websphere 8.5.5 on a cluster environment where i have 2 nodes and on each node there are 3 JVMS

i am configuring the job on application startup.

ISSUE: the job is getting configured one time on each node, and what i expect is that it will be configured only one time on both nodes not one on each node.

my configuration is as follows :

quartzConfig.properties:

#============================================================================
# Configure Main Scheduler Properties  
#============================================================================

org.quartz.scheduler.instanceName = MyJobScheduler
org.quartz.scheduler.instanceId = AUTO
#org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer = true

#============================================================================
# Configure ThreadPool  
#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore  
#============================================================================

org.quartz.jobStore.misfireThreshold = 60000

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate 
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_

org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000

#============================================================================
# Configure Datasources  
#============================================================================

org.quartz.dataSource.myDS.driver = com.microsoft.sqlserver.jdbc.SQLServerDriver
org.quartz.dataSource.myDS.URL = jdbc:sqlserver://mydbserver:51803;databaseName=quartz 
org.quartz.dataSource.myDS.user = quartz
org.quartz.dataSource.myDS.password = quartz
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery=select 1

#============================================================================
# Configure Shutdown Plugin  
#============================================================================

org.quartz.threadPool.makeThreadsDaemons=true
org.quartz.scheduler.makeSchedulerThreadDaemon=true
org.quartz.scheduler.interruptJobsOnShutdown=true
org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin
org.quartz.plugin.shutdownhook.cleanShutdown = true

ApplicationContextListener:

public class ApplicationContextListener implements ServletContextListener {

    private StdSchedulerFactory factoryMyAppJob;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        configureQuartzJobs(event.getServletContext());
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        try {
            factoryMyAppJob.getScheduler().shutdown(false);
        } catch (SchedulerException e) {
            AppLogger.log(e);
        }
    }

    private void configureQuartzJobs(ServletContext servletContext) {

        String currentTime = new SimpleDateFormat("dd_MM_yyyy_HH").format(new Date());
        String myAppGroup = "myAppGroup";
        String myAppJob = "myAppJob";


        try {



            JobDetail job = JobBuilder.newJob(myAppJob.class).withIdentity(myAppJob, myAppGroup).build();

            Trigger triggerMyApp = TriggerBuilder.newTrigger().withIdentity(myAppJob, myAppGroup)
                    .withSchedule(simpleSchedule()
                            .withIntervalInMinutes(3).repeatForever())
                    .build();

            Properties propsMyAppJob = new Properties();

            boolean production = ConfigurationUtils.isProductionEnvironment();

            if (production) {
                propsMyAppJob.load(this.getClass().getClassLoader().getResourceAsStream("quartzConfig.properties"));
                factoryMyAppJob = new StdSchedulerFactory(propsMyAppJob);
            } else {
                factoryMyAppJob = new StdSchedulerFactory();
            }
            Scheduler scheduler = factoryMyAppJob.getScheduler();

            if (scheduler.checkExists(job.getKey())) {
                scheduler.deleteJob(job.getKey());
            }

            scheduler.scheduleJob(job, triggerMyApp);

            scheduler.start();


        } catch (ObjectAlreadyExistsException oae) {

        } catch (Exception e) {
            AppLogger.log(e);
        }
    }

}

please advise how to fix this issue.

1 answer

  • answered 2018-11-08 08:21 Mark Bramnik

    There can be many reasons for this behavior. The configurations seem correct.

    Quartz Documentation mentions the following:

    Never run clustering on separate machines, unless their clocks are synchronized using some form of time-sync service (daemon) that runs very regularly (the clocks must be within a second of each other)

    And another one:

    Never start (scheduler.start()) a non-clustered instance against the same set of database tables that any other instance is running (start()ed) against. You may get serious data corruption, and will definitely experience erratic behavior.

    IMO Both of them can be a valid reason of cluster non functioning properly.