Two quartz workers doing the same job twice

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(); } 
+4
source share
1 answer

The StatefulJob interface and @DisallowConcurrentExecution annotation do the same.

From DisallowConcurrentExecution javadoc :

designates the class of the job as one that should not have multiple instances executed at the same time ....

This can be used instead of implementing the StatefulJob token interface that was used before Quartz 2.0

Setting the threadPool.threadCount property to 1 will mean no more than 1 job of any type .

Using any of these solutions will stop the task at the same time and cause any trigger to be queued, which will be executed when the previous instance of the trigger has completed

+3
source

Source: https://habr.com/ru/post/1382702/


All Articles