/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.terracotta.quartz.tests.rejoin; import com.tc.test.config.model.TestConfig; import com.tc.util.concurrent.ThreadUtil; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobKey; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobPersistenceException; import org.quartz.PersistJobDataAfterExecution; import org.quartz.Scheduler; import org.quartz.SimpleScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.terracotta.toolkit.Toolkit; import org.terracotta.toolkit.concurrent.ToolkitBarrier; import org.terracotta.toolkit.concurrent.atomic.ToolkitAtomicLong; import org.terracotta.toolkit.rejoin.RejoinException; /** * * @author cdennis */ public class TriggerFiringRejoinTest extends AbstractRejoinTest { public TriggerFiringRejoinTest(TestConfig testConfig) { super(testConfig, Client.class, Client.class); } public static class Client extends AbstractRejoinClient { private static final int NUM = 100; private final ToolkitBarrier barrier; private final Toolkit toolkit; public Client(String[] args) { super(args); toolkit = getClusteringToolkit(); barrier = toolkit.getBarrier("barrier", 2); } @Override protected boolean isStartingScheduler() { return false; } @Override public void addSchedulerProperties(Properties properties) { super.addSchedulerProperties(properties); properties.setProperty("org.quartz.threadPool.threadCount", "1"); } @Override protected void test(Scheduler scheduler) throws Throwable { final int ITERATIONS = 5; int index = barrier.await(); for (int cnt = 0; cnt < NUM; cnt++) { if (index == 0) { String jobName = "myJob" + cnt; System.out.println("Scheduling Job: " + jobName); JobDetail jobDetail = JobBuilder.newJob(Client.TestJob.class).withIdentity(jobName) .usingJobData("data", 0).storeDurably().requestRecovery().build(); Trigger trigger = TriggerBuilder .newTrigger() .withIdentity("triggerName" + cnt) .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5) .withRepeatCount(ITERATIONS - 1)).build(); scheduler.scheduleJob(jobDetail, trigger); } } barrier.await(); scheduler.start(); Thread.sleep(10000); if (index == 0) { initiateRejoin(); int doneCount = 0; while (doneCount != NUM) { try { ThreadUtil.reallySleep(1000L); Set<JobKey> completeJobs = new HashSet<JobKey>(); Set<JobKey> incompleteJobs = new HashSet<JobKey>(); for (int i = 0; i < NUM; i++) { String jobName = "myJob" + i; JobDetail jobDetail = scheduler.getJobDetail(new JobKey(jobName)); if (jobDetail.getJobDataMap().getInt("data") >= ITERATIONS) { completeJobs.add(jobDetail.getKey()); } else { incompleteJobs.add(jobDetail.getKey()); } } doneCount = completeJobs.size(); synchronized (System.out) { System.out.println("doneCount: " + doneCount + " incomplete : " + incompleteJobs); if (doneCount > 0) { for (JobKey jk : incompleteJobs) { for (Trigger t : scheduler.getTriggersOfJob(jk)) { System.out.println(t + " " + scheduler.getTriggerState(t.getKey())); } } } } } catch (JobPersistenceException _) { //ignore } } } while (true) { try { barrier.await(); break; } catch (RejoinException e) { while (true) { try { barrier.reset(); break; } catch (RejoinException f) { //nothing to do } } } } scheduler.shutdown(true); } @PersistJobDataAfterExecution @DisallowConcurrentExecution public static class TestJob implements Job { public void execute(JobExecutionContext context) { JobDataMap dataMap = context.getJobDetail().getJobDataMap(); int val = dataMap.getInt("data") + 1; dataMap.put("data", val); System.out.println("Called:" + context.getJobDetail().getKey() + ": " + val); } long incrementAndGet(Map<String, ToolkitAtomicLong> map, String key) { ToolkitAtomicLong current = map.get(key); return current.incrementAndGet(); } } } }