Почему может не срабатывать триггер если вместо периодичности использую запуск по расписанию?
Приложение на spring boot 2 с планировщиком Quartz, база данных Oracle
У меня есть job, которая просто распечатывает сообщение. Есть так же TactConfig класс, где настроены details, trigger, scheduler
У меня возникла следующая проблема с триггером, если при его создании я использую периоды, например
.withSchedule(simpleSchedule().repeatForever().withIntervalInSeconds(5))
то в логах вижу сообщения каждые 5 секунд, с этим все ок.
Но, если я пытаюсь использовать расписания
.withSchedule(CronScheduleBuilder.cronSchedule(TIME))
То сообщения либо вообще не отображаются, или отображаются 1 или 2 раза после старта и все.
Я использую синхронизацию инстансов через базу данных. В sheduler удаляю джобы потому, что при старте приложение ругает что такая джоба уже существует и я удаляю прежнюю чтобы подменить расписание если я его меняю.
Мой класс с бинами:
@Configuration
public class TactConfig {
private Logger logger = LoggerFactory.getLogger(getClass());
private final String QRTZ_TRIGGER = "QRTZ_TACT_TRIGGER";
private final String QRTZ_GROUP = "QRTZ_TACT_GROUP";
private final String QRTZ_JOB = "TACT_JOB";
private final String TIME = "0 0-59 0-23 * * ?"; /* every second an hour */
@Bean
public JobDetail tactJobDetail() {
return JobBuilder
.newJob(TactJob.class)
.storeDurably(true)
.requestRecovery(true)
.withIdentity(new JobKey(QRTZ_JOB, QRTZ_GROUP))
.build();
}
@Bean
public Trigger tactTrigger() {
return TriggerBuilder
.newTrigger()
.withIdentity(new TriggerKey(QRTZ_TRIGGER, QRTZ_GROUP))
.withSchedule(CronScheduleBuilder.cronSchedule(TIME)) /*this doesn't work*/
// .withSchedule(simpleSchedule().repeatForever().withIntervalInSeconds(5)) this works okey
.build();
}
@Bean
public Scheduler scheduler(Trigger trigger, JobDetail job, SchedulerFactoryBean factory)
throws SchedulerException {
Scheduler scheduler = factory.getScheduler();
if (scheduler.checkExists(job.getKey())){
scheduler.deleteJob(job.getKey());
}
scheduler.scheduleJob(job, trigger);
scheduler.start();
return scheduler;
}
}
Сама Джоба
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class TactJob implements Job {
private static final String MESSAGE = "================MY MESSAGE===================";
private Logger logger = LoggerFactory.getLogger(getClass());
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
logger.info(MESSAGE);
}
}
- Пробовал удалять аннотацию @DisallowConcurrentExecution из джобы
- Пробовал подкостылить вот так
@Bean
public Trigger tactTrigger(JobDetail tactJobDetail) throws ParseException {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Assert.isTrue(CronExpression.isValidExpression(TIME), format("некорректно задано расписания для %s", QRTZ_JOB));
return TriggerBuilder
.newTrigger()
.startAt(calendar.getTime())
.startNow()
.withIdentity(new TriggerKey(QRTZ_TRIGGER, QRTZ_GROUP))
.withSchedule(cronSchedule(new CronExpression(TIME)))
// .withSchedule(simpleSchedule().repeatForever().withIntervalInSeconds(5))
.build();
}
Находил на хабре статью и там был такой костыль, но это не помогло Что можно еще попробовать, мне нужно запускать задачу по расписанию только на одном инстансе за раз, иначе можно было бы воспользоваться @Scheduler
Заметил так же такую вещь что при таком формате времени, все отрабатывает - событие происходит раз в 5 секунд
private final String TIME = "0/5 * * ? * * *";
А вот такой формат срабатывает только единожды, а должен каждую минуту
private final String TIME = "0 * * ? * * *";