繁体   English   中英

两个Quartz-Worker两次执行相同的工作

[英]Two Quartz-Worker executing same job twice

我们已经实施了石英调度。每个生产的工作都有不同的关键。到目前为止工作正常。 昨天我们遇到了一个问题,因为两个不同的Quartz-Worker线程正在执行两次或三次相同的工作(没有特定的行为)。 我们不能使线程池大小为1,因为我们需要并发作业。

关于我们预定工作的一个值得注意的事情是它在每次运行时重新安排(每天,每周或每月),即如果一项工作安排在每天运行,那么它将在接下来的24小时内重新安排,但随机预定义(比如说3小时)时间窗口。 例如,如果一份工作今天在4:10(即4:00到7:00之间)运行,那么我们的工作将在4:00到7:00之间的某个随机时间自行重新安排到明天。 它可能是4:01或6:59或5:23或给定时间窗口中的任何其他值。 这个过程也运行良好,大多数情况下仍然可以正常工作,除非在某些情况下我们的重新调度算法未能在接下来的24小时内安排好。 相反,它会在接下来的10秒,1小时或任何其他随机值中安排自己。 但它最终在2-3次错误的重新安排之后稳定了自己,即它最终在接下来的24小时内安排好了。 我们怀疑这可能是由于多个线程访问Calendar对象(我们使用Calendar.getInstance()和cal.add(Calendar.DAY_OF_YEAR,1)在接下来的24小时内重新安排作业)。 某种程度上,日历实例选择了错误的时间,或者无法在当前时间添加一天。

因此,有两个问题:1。多个Quartz线程获取相同的作业2.日历无法添加给定的间隔或在某些特定情况下选择错误的当前时间(多线程访问)

任何帮助将不胜感激。尽快回复。 谢谢。


谢谢你的答复。 我想知道Statefuljob和@DisallowConcurrentExecution注释之间的区别是什么,并将threadPool.threadCount设置为1。

重新安排的代码是......

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

StatefulJob接口和@DisallowConcurrentExecution注释执行相同的操作。

来自DisallowConcurrentExecution javadoc

将Job类标记为不能同时执行多个实例的Job类....

这可以用来代替实现Quartz 2.0之前使用的StatefulJob标记接口

将threadPool.threadCount属性设置为1意味着最多可以执行任何类型的 1个作业

使用任何这些解决方案将停止并发执行的作业,并导致任何触发器被放入队列中,以便在上一个触发器实例完成时执行

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM