Quartz
Данное дополнение позволяет управлять задачами Quartz через пользовательский интерфейс:
-
Создавать новые задачи Quartz из существующей реализации интерфейса
org.quartz.Job. -
Приостанавливать и возобновлять выполнение задач.
-
Запускать немедленное выполнение неактивных задач.
-
Редактировать триггеры и параметры задач.
-
Удалять задачи.
Пользовательский интерфейс управления Quartz доступен через пункт главного меню Quartz → Quartz jobs.
Дополнение также предоставляет Liquibase changelogs для автоматического создания схемы базы данных, необходимой для Quartz.
Установка
Для автоматической установки через Jmix Marketplace следуйте инструкциям в разделе Дополнения.
Для ручной установки добавьте следующие зависимости в ваш build.gradle:
implementation 'io.jmix.quartz:jmix-quartz-starter'
implementation 'io.jmix.quartz:jmix-quartz-flowui-starter'
|
Если URL вашей основной базы данных задан как переменная, заменяющая весь URL (например, Значение зависит от вашей базы данных:
Если переменная в свойстве |
|
Важное примечание для приложений в режиме меню Single mode Если ваше приложение использует режим меню Single mode, вам следует вручную добавить пункты меню после установки дополнения.
Этот шаг необходим, потому что приложения в режиме Single mode не выполняют автоматическое слияние меню дополнений с существующей структурой. |
Использование
Чтобы создать и запланировать задачи для выполнения, сделайте следующее:
-
Создайте класс, реализующий интерфейс
org.quartz.Job. Его методexecute()будет вызываться планировщиком. Например:package com.company.demo.quartz; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SampleJob implements Job { private static final Logger log = LoggerFactory.getLogger(SampleJob.class); @Override public void execute(JobExecutionContext context) throws JobExecutionException { log.info("Sample job is executed"); } }В классе задачи вы можете инжектировать Spring-бины с помощью
@Autowired. -
Запустите приложение, откройте экран Quartz → Quartz jobs и нажмите Create.
-
Введите произвольное уникальное имя в поле Name и выберите ваш класс задачи в поле Class.
Поле Group является необязательным, но может использоваться для группировки задач в пользовательском интерфейсе.
-
Создайте хотя бы один триггер для задачи на вкладке Triggers. Вы можете выбрать тип расписания Cron expression или Simple. В первом случае введите выражение Cron, например
0/5 * * ? * * *(каждые 5 секунд). Во втором случае введите интервал повторения в миллисекундах.
После сохранения триггера и задачи она немедленно планируется для выполнения в соответствии с настройками триггера.
Чтобы отредактировать настройки задачи, сначала приостановите ее, выбрав и нажав Pause. После сохранения изменений вы можете возобновить планирование, нажав Resume.
Вы также можете выполнить любую зарегистрированную задачу немедленно, нажав Execute now, даже если у задачи нет триггеров. Это полезно для тестирования.
-
Программная настройка задач и триггеров
Вместо создания задач и триггеров Quartz на экране Quartz jobs их можно зарегистрировать как Spring-бины. Такой подход полезен, когда расписание должно быть определено вместе с кодом приложения.
Объявите эти бины в классе конфигурации Spring, расположенном в пакете, который сканируется приложением.
import com.company.demo.quartz.SampleJob;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuartzConfiguration {
@Bean
JobDetail sampleJob() {
return JobBuilder.newJob()
.ofType(SampleJob.class) (1)
.storeDurably()
.withIdentity("SampleJob") (2)
.build();
}
@Bean
Trigger sampleJobTrigger() {
return TriggerBuilder.newTrigger()
.forJob(sampleJob()) (3)
.withIdentity("SampleJobTrigger") (4)
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) (5)
.build();
}
}
| 1 | Класс реализации задачи. |
| 2 | Идентификатор задачи. |
| 3 | Связывает триггер с задачей. |
| 4 | Идентификатор триггера. Указывайте его явно, чтобы избежать создания дублирующих триггеров после повторного развертывания. |
| 5 | Cron-расписание. |
withIdentity() задает идентификатор Quartz для задачи или триггера. Всегда указывайте идентификатор для каждого триггера, созданного в коде.
Если у триггера нет явного идентификатора, Quartz генерирует случайный идентификатор. Когда приложение использует постоянные таблицы Quartz, это может приводить к созданию нового триггера при каждом повторном развертывании. В результате несколько триггеров будут выполнять одну и ту же задачу по одному и тому же расписанию.
Аутентификация в задачах
Код, выполняемый планировщиком, не аутентифицирован, то есть не ассоциирован с каким-либо пользователем.
Если вы вызываете операции, требующие аутентификации, например, работу с данными через DataManager, используйте SystemAuthenticator или аннотацию @Authenticated:
public class SampleAuthenticatedJob implements Job {
private static final Logger log = LoggerFactory.getLogger(SampleAuthenticatedJob.class);
@Autowired
private DataManager dataManager;
@Authenticated
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
int usersCount = dataManager.load(User.class).all().list().size();
log.info("There are {} registered users", usersCount);
}
}
Вы также можете использовать UnconstrainedDataManager для работы с данными в неаутентифицированном контексте.
|
Параметры задачи
Экран Job editor позволяет задать параметры для экземпляра задачи на вкладке Job data parameters. Вы можете использовать параметры в классе задачи следующим образом:
public class SampleParameterizedJob implements Job {
private static final Logger log = LoggerFactory.getLogger(SampleParameterizedJob.class);
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String paramStr = jobDataMap.entrySet().stream()
.map(e -> e.getKey() + " : " + e.getValue())
.collect(Collectors.joining(", ", "[", "]"));
log.info("Sample job is executed with parameters: " + paramStr);
}
}
Отслеживание выполнения задач
Если вы хотите отслеживать выполнение задач, создайте бин, реализующий интерфейс JobListener или расширяющий JobListenerSupport следующим образом:
package com.company.demo.quartz;
import jakarta.annotation.PostConstruct;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.listeners.JobListenerSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class JobExecutionListener extends JobListenerSupport {
private static final Logger log = LoggerFactory.getLogger(JobExecutionListener.class);
@Autowired
private Scheduler scheduler;
@Override
public String getName() {
return "SampleJobExecutionListener";
}
@PostConstruct
private void registerListener() { (1)
try {
scheduler.getListenerManager().addJobListener(this);
} catch (SchedulerException e) {
log.error("Cannot register job listener", e);
}
}
@Override
public void jobWasExecuted(JobExecutionContext context,
JobExecutionException jobException) { (2)
log.info("jobWasExecuted: name={}, context={}",
context.getJobDetail().getKey().getName(), context);
}
}
| 1 | Вызывается Spring после создания экземпляра бина. |
| 2 | Вызывается планировщиком Quartz после выполнения задачи. |
В методе jobWasExecuted() вы можете сохранить информацию о выполненной задаче в журнале или в базе данных.