ObjectAlreadyExistsException:Unable to store Job : '*', because one already exists with thi s ident

#Quartz# 

现象描述 :

      项目启动要初始化程序配置的各个job, 采用的是quartz,但是发现有时候启动时报错:org.quartz.ObjectAlreadyExistsException: Unable to store Job : 'MONITOR_RUNNER_GROUP.indexWarningRunner', because one already exists with thi
s identification, job存储失败。

        查看quartz数据库: cron_triggers,里面没有 MONITOR_RUNNER_GROUP.indexWarningRunner, job_details库里面有,triggers库里面没有。

开始做法:

存不进去是因为里面已经有了,删除job_details里面的,启动正常,但是后续还会出现这种情况。代码逻辑有问题,不是什么quartz bug。

排查:

   初始化quartz任务代码:

public void init() throws Exception {
        Map<String, BaseRunner> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType(BaseRunner.class);
        for (String name : beansOfType.keySet()) {
            BaseRunner baseRunner = beansOfType.get(name);
            JobKey jobKey = new JobKey(name, RunnerConstants.RUNNER_GROUP);
            TriggerKey triggerKey = new TriggerKey(name, RunnerConstants.RUNNER_GROUP);

            RunnerCron annotation = baseRunner.getClass().getAnnotation(RunnerCron.class);
            if (annotation == null) {
                LOG.warn("monitor schedule: {} create failed, cron is missing", jobKey.toString());
                this.tryDeleteJob(jobKey);
                continue;
            }
            String cron = this.getProperties(annotation.value());
            if (StringUtils.isNotBlank(cron)) {
                JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
                jobDetailFactoryBean.setGroup(RunnerConstants.RUNNER_GROUP);
                jobDetailFactoryBean.setName(name);
                jobDetailFactoryBean.setDurability(true);
                jobDetailFactoryBean.setJobClass(RunnerJob.class);
                jobDetailFactoryBean.getJobDataMap().put(RunnerConstants.RUNNER_NAME, name);
                jobDetailFactoryBean.afterPropertiesSet();
                JobDetail jobDetail = jobDetailFactoryBean.getObject();

                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
  
                if (Objects.isNull(trigger) ) {
                    CronTrigger cronTrigger =          TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(cron)).startNow().build();
                    scheduler.scheduleJob(jobDetail, cronTrigger);
                    LOG.info("monitor schedule: {} created", triggerKey.toString());
                } else {
                    CronTrigger cronTrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(cron)).startNow().build();
                    scheduler.rescheduleJob(triggerKey, cronTrigger);
                    LOG.info("monitor schedule: {} refreshed", triggerKey.toString());
                }

            } else {
                LOG.warn("monitor schedule: {} create failed, cron is invalid", jobKey.toString());
                this.tryDeleteJob(jobKey);
            }
        }
    }

  private void tryDeleteJob(JobKey jobKey) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup());
        scheduler.pauseTrigger(triggerKey);
        //这句话是先删除相关的trigger触发器,如果trigger关联的job没有其他触发器并且不持续,也被删除(duarble为true,只删除trigger,job还在保留)
        //否则下次启动就有可能存储job的时候报错
        //scheduler.unscheduleJob(triggerKey);

        //会删除joddetail,以及其关联的triggers
        scheduler.deleteJob(jobKey);
    }

可以看出来,如果trigger 是空,但是job 数据库还是有的。然后scheduleJob方法,存储job报错了。

最终做法是:

   虽然,一个job可以绑定多个trigger,一个trigger只能有一个job, 但是这里就做成了一对一的关系,避免混乱:判断trigger和jobDetail 有没有,都有,就更新trigger,否则deleteJob ,然后新建。或者,启动的时候一并删除,然后全部新建

 

 

 

 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值