Сохранение данных структуры JobDataMap при перезапуске приложения

Здравствуйте!
Столкнулся с тем, что данные, которые я сохраняю в JobDataMap внутри джобов после перезапуска приложения очищаются. Хотя пока приложение работает данные сохраняются, они доступны на каждой итерации выполнения джоба и их даже можно увидеть в UI. Можно ли как то добиться, чтобы данные не пропадали между перезапусками приложения.

Данные записываются вот так:

@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class StorageLocationImportJob implements Job {

public void execute(JobExecutionContext context) throws JobExecutionException {               
        JobDataMap dataMap = context.getJobDetail().getJobDataMap();        
        String prevSyncDate = dataMap.getString("syncDate");         
        ......  
        dataMap.put("syncDate", TimeUtils.dateTimeToString(syncDate));
}

}
1 симпатия

Добрый день!
Попробовал воспроизвести вашу проблему - у меня параметры сохраняются и восстанавливаются после перезапуска джобы. Если получится, приложите, пожалуйста, демо-проект на котором воспроизводится ошибка.

lab-jmix-jobs.zip (81.6 КБ)
Приложил проект, где воспроизводится проблема. Такое впечатление, что всякий раз при перезапуске приложения создается новый джоб и, соответственно, состояние у него чистое. Хотелось бы, чтобы джоб был не новый, а привязан к уже существующему в БД экземпляру джоба с заполненным состоянием. Может быть я как-то не так джоб конфигурирую.

Я делаю так:

@Configuration
public class JobsConfig {

    public static final String JOB_TRIGGER_NAME = "testJobTrigger";
    public static final String JOB_NAME = "testJob";
    public static final String JOB_GROUP = "testJobGroup";

    @Bean
    Trigger testJobTriggerTrigger() {
        Date now = new Date();
        Date afterTenSeconds = new Date(now.getTime() + 10000);
        return TriggerBuilder.newTrigger()
                .withIdentity(JOB_TRIGGER_NAME)
                .forJob(testJob())
                .startAt(afterTenSeconds)
                .withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?"))
                .build();
    }

    @Bean
    JobDetail testJob() {
        return JobBuilder.newJob()
                .ofType(TestJob.class)
                .storeDurably()
                .withIdentity(JOB_NAME, JOB_GROUP)
                .build();
    }
}

Каждый раз, при запуске приложения я вижу пустое состояние джоба:

2022-09-17 09:16:40.976  INFO 11548 --- [eduler_Worker-1] ru.ab.lab.jmix.jobs.TestJob              : RUN TestJob {prevSyncDate: null...}
2022-09-17 09:16:50.009  INFO 11548 --- [eduler_Worker-2] ru.ab.lab.jmix.jobs.TestJob              : RUN TestJob {prevSyncDate: 2022-09-17T09:16:40.977+03:00...}
2022-09-17 09:17:00.006  INFO 11548 --- [eduler_Worker-3] ru.ab.lab.jmix.jobs.TestJob              : RUN TestJob {prevSyncDate: 2022-09-17T09:16:50.009+03:00...}

Причина в том, что аддон Quartz внутри себя ставит свойство

spring.quartz.overwrite-existing-jobs=true

Т.е. при каждом перезапуске приложения джобы пересоздаются. Это сделано для того, чтобы при изменении cron-выражения в бине была создана джоба с новым выражением, иначе джоба продолжается выполняться со старым расписанием.

Если вы поставите в application.properties

spring.quartz.overwrite-existing-jobs=false

то параметры джобы будут сохраняться, но имейте в виду, что если CRON выражение вы поменяете в коде, то оно применено не будет.

У меня ошибка не воспроизводилась, потому что я регистрировал джобы не через создание бина, а через экран приложения.

1 симпатия

Максим, спасибо большое за помощь! Всё так и есть: выставил параметр spring.quartz.overwrite-existing-jobs=false и всё заработало как надо. :handshake:
Странно, конечно, что так сделано. У джоба есть имя, можно было бы его и не пересоздавать, если у него имя не меняется. Но это, конечно, вопрос к разработчикам библиотеки Quartz. Возможно у них были на то причины. Спасибо!

У спринга по умолчанию как раз false там и стоит, то есть по умолчанию джобы не пересоздаются. (см. доку по spring boot).
Пересоздание джоб включено уже в нашем аддоне Jmix. Это сделано из-за того, что у многих стандартных аддонов (например отправка почты) расписание планировщика задаётся конфигурационным свойством. И если джобы не пересоздавать, то изменение значения этого свойства по ходу жизни приложения никак не подхватится.

1 симпатия