We have implemented quartz for planning. Each work done has different keys. So far, it has worked fine. Yesterday we are faced with a problem, since the same work is performed twice or thrice (without any special behavior) by two different Quartz-Worker threads. We cannot make the thread pool size one, because we need parallel jobs.
One noticeable thing about our planned task is that it regresses (daily, weekly or monthly) itself at each start, that is, if the task is scheduled to be launched daily, it will reschedule itself in the next 24 hours, but with a random predefined ( say 3 hours). For example, if the work was performed today at 4:10 (i.e. between 4:00 and 7:00), then our work will redirect it to tomorrow at any time between 4:00 and 7:00. It can be 4:01 or 6:59 or 5:23 or any other value in this time window. This process also worked fine, and it still works fine for most cases, except when our reagent algorithm does not plan to plan itself in the next 24 hours. Instead, he plans himself in the next 10 seconds, 1 hour, or any other random value. But it finally stabilizes after 2-3 such improper redevelopments, i.e. He finally plans himself in the next 24 hours. We suspect that this may happen because several threads are accessing the Calendar object (we use Calendar.getInstance () and cal.add (Calendar.DAY_OF_YEAR, 1) to postpone work in the next 24 hours). Somehow, the calendar instance is choosing the wrong time or cannot add one day to the current time.
So, there are two problems: 1. Several quartz threads getting the same job 2. The calendar cannot add the specified interval or collects the wrong current time in some cases (access to multiple threads)
Any help would be appreciated. Thanks.
Thanks for the answer. I would like to know what is the difference between Statefuljob annotation and @DisallowConcurrentExecution and setting threadPool.threadCount to 1.
The code for rescheduling is ...
Calendar cal = Calendar.getInstance(); Calendar nextCal = Calendar.getInstance(); cal.setTimeZone(TimeZone.getTimeZone(obj.getTimeZone())); nextCal.setTimeZone(TimeZone.getTimeZone(obj.getTimeZone())); Date startTime = null; SimpleTrigger trigger = null; JobDataMap dataMap = new JobDataMap(); if (repeatTimeInMillis == null) { cal.set(Calendar.HOUR_OF_DAY, obj.getStartTime()); nextCal.set(Calendar.HOUR_OF_DAY, obj.getStartTime()); cal.set(Calendar.MINUTE, 0); nextCal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); nextCal.set(Calendar.SECOND, 0); if (obj.getScheduleType() == ScheduleType.MONTHLY) { // Monthly log.info("in monthly schedule"); nextCal.add(Calendar.MONTH, 2); nextCal.set(Calendar.DAY_OF_MONTH, obj.getDate()); cal.add(Calendar.MONTH, 1); cal.set(Calendar.DAY_OF_MONTH, obj.getDate()); } else if (obj.getScheduleType() == ScheduleType.WEEKLY) { // Weekly log.info("in weekly schedule"); nextCal.add(Calendar.WEEK_OF_YEAR, 2); nextCal.set(Calendar.DAY_OF_WEEK, obj.getDay()); cal.add(Calendar.WEEK_OF_YEAR, 1); cal.set(Calendar.DAY_OF_WEEK, obj.getDay()); } else if (obj.getScheduleType() == ScheduleType.DAILY) { // Daily log.info("in daily schedule"); nextCal.add(Calendar.DAY_OF_YEAR, 2); cal.add(Calendar.DAY_OF_YEAR, 1); } long time = obj.getTimeWindow() * 60 * 60 * 1000; time = Math.round(time * Math.random()); cal.setTimeInMillis(cal.getTimeInMillis() + time); startTime = cal.getTime(); nextCal.setTimeInMillis(nextCal.getTimeInMillis() + time); repeatTimeInMillis = nextCal.getTimeInMillis() - cal.getTimeInMillis(); log.info("Rescheduling job at " + startTime); trigger = newTrigger().usingJobData(dataMap) .withIdentity(obj.getScheduleJobName(), obj.getScheduleJobGroup()).startAt(startTime) .withSchedule(simpleSchedule().withIntervalInMilliseconds(repeatTimeInMillis).repeatForever()) .build(); } else { log.info("Rescheduling job next " + repeatTimeInMillis + " milliseconds."); cal.setTimeInMillis(cal.getTimeInMillis() + repeatTimeInMillis); startTime = cal.getTime(); trigger = newTrigger().usingJobData(dataMap) .withIdentity(obj.getScheduleJobName(), obj.getScheduleJobGroup()).startAt(startTime) .withSchedule(simpleSchedule().withIntervalInMilliseconds(repeatTimeInMillis).withRepeatCount(1)).build(); }