Quartz не работает должным образом в кластерной среде

Я использую quartz-2.2.3 в Websphere 8.5.5 в кластерной среде, где у меня есть 2 узла, и на каждом узле есть 3 JVMS.

Я настраиваю задание при запуске приложения.

Проблема в том, что задание настраивается один раз на каждом узле, и я ожидаю, что оно будет настроено только один раз на обоих узлах, а не по одному на каждом узле.

Моя конфигурация выглядит следующим образом:

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);
        }
    }

}

person Mahmoud Saleh    schedule 08.11.2018    source источник


Ответы (1)


Причин такого поведения может быть много. Конфигурации кажутся правильными.

В Quartz Documentation упоминается следующее:

Никогда не запускайте кластеризацию на отдельных машинах, если только их часы не синхронизированы с помощью какой-либо службы синхронизации времени (демона), которая работает очень регулярно (часы должны быть в пределах секунды друг от друга).

И еще один:

Никогда не запускайте (scheduler.start()) некластеризованный экземпляр для того же набора таблиц базы данных, с которым работает любой другой экземпляр (start()ed). Вы можете столкнуться с серьезным повреждением данных и определенно столкнетесь с неустойчивым поведением.

IMO Оба они могут быть уважительной причиной неправильной работы кластера.

person Mark Bramnik    schedule 08.11.2018
comment
поэтому я думаю, что лучшим решением здесь является настройка задания только на одном узле. - person Mahmoud Saleh; 08.11.2018
comment
Ну, это действительно зависит от ваших требований. В целом кварцевый кластер работает. Если узел, на котором размещен кварц, выходит из строя, то отказоустойчивость должна выполняться автоматически. - person Mark Bramnik; 08.11.2018