Рубрики
Без рубрики

Руководство по Quartz с весенней загрузкой – Планирование и автоматизация заданий

Узнайте, как создать собственную консоль управления Quartz с помощью Java и Spring Boot – выполняйте планирование заданий и автоматизацию с помощью одного из мощных планировщиков.

Автор оригинала: Arpendu Kumar Garai.

Вступление

Время дорого и делегирование времени и ресурсов для выполнения рутинных задач приводит к пустой трате ресурсов и денег. Следовательно, организации стремятся достичь полномасштабной автоматизации в своих системах, поскольку она намного масштабируема и значительно дешевле.

По мере усложнения бизнес-процессов возрастает и преимущество автоматизации в системе.

Автоматизация – это то, где преобладают концепции Рабочих мест или Графиков . Планирование заданий часто называют любым видом пакета процессов (заданий), выполняемых в заданное время. Поскольку большинство этих заданий не требуют немедленного выполнения, их можно запланировать для обработки в ближайшем будущем или через повторяющиеся интервалы времени.

В целом, автоматизация любого процесса с использованием ручного подхода приводит к:

  • Эффективность Использования Ресурсов
  • Меньше ошибок
  • Большая масштабируемость

Одна из самых мощных и гибких систем планирования, используемых для крупномасштабных приложений Java, известна как Quartz .

В этом руководстве мы будем внедрять Quartz и его компоненты в приложение Spring Boot, создавая нашу собственную консоль управления Quartz для пользовательских Заданий и Триггеров .

Примечание: Работоспособная, полноценная копия Консоли управления Quartz , которую мы будем создавать, доступна на нашем GitHub .

Планировщик заданий Quartz

Quartz -это фреймворк планирования заданий с открытым исходным кодом, написанный на Java и предназначенный для интеграции с любым типом фреймворка J2EE или J2SE. Он обеспечивает огромную гибкость без ущерба для сложности или масштабируемости.

Название, предположительно, происходит от кварцевого кристалла , используемого в чрезвычайно точных часах и часах, которые при электрическом колебании перемещают стрелки часов в обычное время.

Если ожидается, что приложение будет выполнять задачи с запланированными интервалами или в связи с некоторыми событиями, Quartz отлично подойдет:

  • Запуск напоминаний или предупреждений по электронной почте : вы можете легко запускать сообщения с истекшим сроком действия пароля или другие виды напоминаний для разных пользователей в зависимости от активности учетной записи.
  • Выполнение операций передачи файлов или обмена сообщениями : Задания можно легко планировать через определенные промежутки времени для публикации/использования сообщений/данных/файлов от различных брокеров или FTP-сайтов.
  • Автоматическое создание отчетов : Компании часто предпочитают создавать еженедельные/еженедельные отчеты для демонстрации эффективности бизнеса. Эти задания могут легко создавать отчеты и отправлять электронные письма сотрудникам в запланированное время.
  • Управление рабочим процессом задачи : Крупные организации электронной коммерции могут планировать выполнение задания точно через определенные промежутки времени, чтобы выбрать заказ из канала и обработать его для выполнения или проявления.

Некоторые из характерных особенностей кварца являются:

  • Он может быть создан в контейнере сервера приложений или сервлета и может участвовать в транзакциях XA.
  • Он может быть размещен в виде кластера автономных программ (с возможностью балансировки нагрузки и отработки отказа) для выполнения заданий.
  • Задания планируются для выполнения при возникновении триггера, например, в определенное время суток, определенные дни недель, месяцев или лет, пропуск выполнения в праздничные дни, повторное выполнение до определенной даты или на неопределенный срок и т.д.
  • Задания могут сохраняться либо в памяти, либо в любом хранилище данных JDBC.
  • Он может участвовать в транзакциях JTA.

Ключевые компоненты модели планировщика Quartz

Для улучшения масштабируемости Quartz работает в многопоточной среде. Это помогает платформе выполнять задания одновременно.

Сердцем общей структуры является интерфейс Планировщик . Планировщик отслеживает все Список заданий и Триггеры для них. Они представляют что необходимо выполнить (какое Задание ) и когда (что Запускает это задание).

Таким образом, они образуют основные компоненты структуры. Остальные остальные компоненты обеспечивают, чтобы это происходило с должной осмотрительностью и эффективно.

Давайте взглянем орлиным глазом на ключевые компоненты, которые мы будем использовать:

  • Фабрика планировщика – Компонент фабрики, который отвечает за построение модели Планировщика и подключение всех зависимых компонентов на основе содержимого файла свойств quartz.
  • Планировщик – Поддерживает Список заданий |//Триггер реестр. Он также отвечает за выполнение связанных заданий при срабатывании триггера. Поток планировщика
  • – Поток, ответственный за выполнение работы по запуску триггеров. Он связывается с Магазином заданий , чтобы получить следующий набор триггеров для запуска. Задание
  • – Интерфейс, который должен быть реализован выполняемой задачей. Триггер
  • – Указывает планировщику время выполнения соответствующего задания. JobStore
  • – Интерфейс, реализуемый классами, обеспечивающими механизм хранения Заданий и триггеров. Пул потоков
  • – Выполняемое задание передается в пул потоков, представленный пулом потоков . Рабочие потоки
  • – Отдельные потоки, которые создают Пул потоков и выполняют задания.

Создание консоли управления Quartz

Мы создадим вашу собственную Консоль управления Quartz , чтобы получить представление и оценить жизненные циклы в планировщике Quartz.

С этой целью мы создадим простую консоль управления, управляемую пользовательским интерфейсом, которая может выполнять два вида задач:

  • Планируйте и управляйте простой работой
  • Планирование и управление заданием Cron

Это будет выглядеть примерно так после внедрения:

Настройка проекта

Давайте создадим проект Spring Boot и реализуем каждый компонент Quartz один за другим. Самый простой способ начать со скелетного проекта-это Spring Initializr :

Мы добавили Spring Web для функций MVC, Spring Data JPA для хранения данных в хранилище данных, H2 в качестве базы данных в памяти, Ломбок (дополнительная библиотека для сокращения шаблонов) и Thymeleaf (Механизм шаблонов для приложений Spring/MVC). Мы также включили пакет spring-boot-starter-quartz , чтобы включить Кварц в наш проект.

Подключение и инициализация базы данных

Кварц приносит свои собственные встроенные Магазины вакансий . В весенней загрузке мы можем выбирать между:

  • Хранилища заданий в памяти : Храните все данные в оперативной памяти, чтобы при остановке или сбое приложения все данные сбрасывались и вся информация о планировании терялась. Для этого мы используем RAMJobStore .
  • JDBC Jobstore : Сохраняйте все данные в хранилище данных, чтобы данные не были потеряны. Конфигурация немного сложнее, чем хранилища заданий в оперативной памяти (ОЗУ).

Примечание: Вы можете выбрать эти типы JobStore независимо от вашей базы данных.

Мы будем использовать H2 в качестве хранилища данных и настраивать Quartz для сохранения данных.

Quartz требует, чтобы вы инициализировали таблицы базы данных для JDBC Jobstore, так как они не создаются автоматически. С этой целью мы будем использовать сценарий SQL для запуска при инициализации базы данных. Вы можете найти сценарий инициализации на нашем GitHub .

Давайте начнем разработку нашего приложения для управления с определения параметров подключения к базе данных для H2. В вашем файле application.properties давайте определим init.schema (сценарий начальной установки), а также источник данных параметры:

server.port=8080

spring.sql.init.schema-locations=classpath:db/quartz_tables_h2.sql
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=

logging.level.org.hibernate.SQL=debug

Сценарий quartz_tables_h2.sql состоит из длинного набора команд SQL, используемых для его первоначальной настройки:

-- Note, Quartz depends on row-level locking which means you must use the MVC=TRUE
-- setting on your H2 database, or you will experience dead-locks
--
-- In your Quartz properties file, you'll need to set
-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

CREATE TABLE QRTZ_CALENDARS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  CALENDAR_NAME VARCHAR (200)  NOT NULL ,
  CALENDAR IMAGE NOT NULL
);

...
-- Download the entire script from our GitHub repository
...

COMMIT;

Свойства Кварца

Как только соединение с базой данных будет установлено и у нас будет готов сценарий инициализации, мы захотим настроить планировщик Quartz и его компоненты.

Большинство аспектов и компонентов в определенной степени настраиваются, например, какие драйверы JobStore должны использоваться, сколько потоков находится в Пуле потоков и какой у них приоритет и т.д.

Все они определены в файле quartz.properties , который должен находиться в разделе /src/ресурсы/|/. Это каталог, в котором класс Quartz Properties по умолчанию ищет требуемые свойства.

Примечание: Если вы хотите определить его в другом файле свойств, вам нужно указать свойство org.quartz.properties system, чтобы указать на этот файл.

Давайте теперь определим некоторые свойства:

#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName=spring-boot-quartz
org.quartz.scheduler.instanceId=AUTO 

#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold=1000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.tablePrefix=QRTZ_


#============================================================================
# Configure Cluster properties
#============================================================================
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=1000

Определение компонента Фабрики заданий планировщика

Все эти свойства мало что значат, если мы не используем их в классе @Configuration для настройки работы Quartz. Давайте введем свойства из quartz.properties в класс Конфигурация планировщика , где мы инициализируем класс SchedulerJobFactoryBean , передав свойства.

Мы будем реализовывать наш собственный Планировщик JobFactory, который будет как SpringBeanJobFactory из проекта Quartz:

@Configuration
public class SchedulerConfig {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private QuartzProperties quartzProperties;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {

        SchedulerJobFactory jobFactory = new SchedulerJobFactory();
        jobFactory.setApplicationContext(applicationContext);

        Properties properties = new Properties();
        properties.putAll(quartzProperties.getProperties());

        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setOverwriteExistingJobs(true);
        factory.setDataSource(dataSource);
        factory.setQuartzProperties(properties);
        factory.setJobFactory(jobFactory);
        return factory;
    }
}

Класс Свойства кварца содержит свойства, определенные в файле quartz.properties . Мы можем получить их с помощью GetProperties() и добавить их в SchedulerFactoryBean вместе с Источником данных и SchedulerJobFactory .

Планировщик JobFactory – это наша пользовательская реализация SpringBeanJobFactory , которую предоставляет нам Quartz. Давайте расширим его:

public class SchedulerJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

    private AutowireCapableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}

Теперь мы можем создавать рабочие места на нашем заводе и подключать его автоматически, когда это необходимо. На этом этапе – мы можем вызвать запущенный экземпляр планировщика Quartz. Если мы запустим наше приложение, нас встретят чем-то вроде:

Определение создателя универсального планировщика заданий

В Quartz есть два типа триггеров – CronTrigger и Простой триггер . Они соответствуют планировщику Cron и SimpleScheduler соответственно, и мы можем создавать триггеры, используя их соответствующие фабрики.

/| CronTrigger запускает триггеры на основе выражения cron , в то время как Простой триггер запускает на интервале.

Чтобы создать триггеры заданий, давайте определим несколько удобных методов, которые создают экземпляры и возвращают их через соответствующие фабрики. Эти методы будут расположены в Планировщике заданий Create – a @Component , который мы будем использовать для создания заданий и триггеров:

@Component
public class JobScheduleCreator {
    // Creation methods
}

Давайте начнем с метода CronTrigger creator:

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

public CronTrigger createCronTrigger(String triggerName, Date startTime, String cronExpression, int misFireInstruction) {
    CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
    factoryBean.setName(triggerName);
    factoryBean.setStartTime(startTime);
    factoryBean.setCronExpression(cronExpression);
    factoryBean.setMisfireInstruction(misFireInstruction);
    try {
      factoryBean.afterPropertiesSet();
    } catch (ParseException e) {
      log.error(e.getMessage(), e);
    }
    return factoryBean.getObject();
}

Используя CronTriggerFactoryBean , мы передаем необходимую информацию о триггере , такую как его имя, время запуска, а также выражение cron и инструкцию по пропуску. После создания – объект возвращается.

Почти тот же процесс применяется для создания Простого триггера объектов:

public SimpleTrigger createSimpleTrigger(String triggerName, Date startTime, Long repeatTime, int misFireInstruction) {
    SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
    factoryBean.setName(triggerName);
    factoryBean.setStartTime(startTime);
    factoryBean.setRepeatInterval(repeatTime);
    factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
    factoryBean.setMisfireInstruction(misFireInstruction);
    factoryBean.afterPropertiesSet();
    return factoryBean.getObject();
}

С помощью простого способа создания триггеров мы также можем создать удобный метод создания заданий – опираясь на JobDetailFactoryBean :

public JobDetail createJob(Class jobClass, boolean isDurable,
                           ApplicationContext context, String jobName, String jobGroup) {
    JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
    factoryBean.setJobClass(jobClass);
    factoryBean.setDurability(isDurable);
    factoryBean.setApplicationContext(context);
    factoryBean.setName(jobName);
    factoryBean.setGroup(jobGroup);

    // Set job data map
    JobDataMap jobDataMap = new JobDataMap();
    jobDataMap.put(jobName + jobGroup, jobClass.getName());
    factoryBean.setJobDataMap(jobDataMap);
    factoryBean.afterPropertiesSet();
    return factoryBean.getObject();
}

Определение сущности Сведений о задании планировщика

Чтобы отслеживать детали и информацию о работе – мы можем использовать Сведения о работе класс. Вот для чего это предназначено. Однако мы можем извлечь выгоду из определения собственного прокси-сервера для этого класса.

Не рекомендуется писать в таблицы Quartz напрямую самим , поэтому задания и их детали, хотя и сохраняются, исправлены. Мы можем определить новую сущность для отслеживания этих заданий в отдельной таблице и делать с ними все, что пожелаем, а также использовать эти объекты в качестве Объектов передачи данных (DTOs) одновременно.

Это позволяет нам выполнять проверку входящих данных и обеспечивает более детальный контроль над сохранением заданий в базе данных.

Хотя это необязательно, рекомендуется использовать такой прокси – сервер-мы назовем его SchedulerJobInfo :

// Lombok annotations for getters, setters and constructor
public class SchedulerJobInfo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String jobId;
    private String jobName;
    private String jobGroup;
    private String jobStatus;
    private String jobClass;
    private String cronExpression;
    private String desc;    
    private String interfaceName;
    private Long repeatTime;
    private Boolean cronJob;
}

Для простой функциональности CRUD – мы создадим простой JpaRepository для этой сущности:

@Repository
public interface SchedulerRepository extends JpaRepository {
    SchedulerJobInfo findByJobName(String jobName);
}

Выполнение заданий в Quartz – Работа и QuartzJobBean

Каждое задание должно либо расширить класс QuartzJobBean , либо реализовать интерфейс Job .

QuartzJobBean реализует Задание и единственная разница в том, что QuartzJobBean применяет переданные JobDataMap и SchedulerContext в качестве значений свойств компонента, тогда как Задание этого не делает.

Кроме того, Задание требует реализации метода execute () , в то время как QuartzJobBean требует реализации метода executeInternal () .

Давайте создадим Простое задание , которое расширяет QuartzJobBean и выводит целые числа из 0 чтобы 5 :

public class SimpleJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        log.info("SimpleJob Start................");
        IntStream.range(0, 5).forEach(i -> {
            log.info("Counting - {}", i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
        });
        log.info("SimpleJob End................");
    }
}

Аналогично, мы можем создать Простое задание Cron , которое запускает определенное выражение cron:

@DisallowConcurrentExecution
public class SimpleCronJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        log.info("SimpleCronJob Start................");
        IntStream.range(0, 10).forEach(i -> {
            log.info("Counting - {}", i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
        });
        log.info("SimpleCronJob End................");
    }
}

Примечание: Мы применяем @DisallowConcurrentExecution , чтобы это задание не выполнялось несколькими планировщиками одновременно в кластеризованной настройке.

Определение пользовательских утилит для действий

В консоли управления Quartz у нас будет несколько вариантов заданий:

  • Создавать
  • Редактировать
  • Беги Один Раз
  • Пауза
  • Возобновиться
  • Удалить

Они позволяют нам создавать, редактировать, приостанавливать, возобновлять, удалять и запускать задание один раз. Чтобы облегчить это – мы напишем методы для каждой задачи, позволяющие нам управлять заданиями с помощью действительно простого и интуитивно понятного пользовательского интерфейса.

Чтобы связать все это воедино, мы создадим новый класс – Службу заданий Планировщика для выполнения этих действий:

@Transactional
@Service
public class SchedulerJobService {

	@Autowired
	private Scheduler scheduler;

	@Autowired
	private SchedulerFactoryBean schedulerFactoryBean;

	@Autowired
	private SchedulerRepository schedulerRepository;

	@Autowired
	private ApplicationContext context;

	@Autowired
	private JobScheduleCreator scheduleCreator;
	
	// Create, edit, pause jobs, etc...
Создайте задание Quartz

Для создания заданий собственный метод saveOrUpdate() определяет, должен ли экземпляр, созданный с помощью определенного SchedulerJobInfo DTO, быть сохранен в существующей сущности или должно быть создано новое задание. Основываясь на параметрах полезной нагрузки, мы либо создадим Простое задание Cron , либо Простое задание :

public void saveOrUpdate(SchedulerJobInfo scheduleJob) throws Exception {
	if (scheduleJob.getCronExpression().length() > 0) {
		scheduleJob.setJobClass(SimpleCronJob.class.getName());
		scheduleJob.setCronJob(true);
	} else {
		scheduleJob.setJobClass(SimpleJob.class.getName());
		scheduleJob.setCronJob(false);
		scheduleJob.setRepeatTime((long) 1);
	}
	if (StringUtils.isEmpty(scheduleJob.getJobId())) {
		log.info("Job Info: {}", scheduleJob);
		scheduleNewJob(scheduleJob);
	} else {
		updateScheduleJob(scheduleJob);
	}
	scheduleJob.setDesc("i am job number " + scheduleJob.getJobId());
	scheduleJob.setInterfaceName("interface_" + scheduleJob.getJobId());
	log.info(">>>>> jobName = [" + scheduleJob.getJobName() + "]" + " created.");
}

Если задание не существует – мы вызываем планировщик нового задания () , который планирует новое задание, используя наш автоматический Создатель расписания заданий компонент из предыдущих:

private void scheduleNewJob(SchedulerJobInfo jobInfo) {
	try {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();

		JobDetail jobDetail = JobBuilder
				.newJob((Class) Class.forName(jobInfo.getJobClass()))
				.withIdentity(jobInfo.getJobName(), jobInfo.getJobGroup()).build();
		if (!scheduler.checkExists(jobDetail.getKey())) {

			jobDetail = scheduleCreator.createJob(
					(Class) Class.forName(jobInfo.getJobClass()), false, context,
					jobInfo.getJobName(), jobInfo.getJobGroup());

			Trigger trigger;
			if (jobInfo.getCronJob()) {
				trigger = scheduleCreator.createCronTrigger(
				        jobInfo.getJobName(), 
				        new Date(),
						jobInfo.getCronExpression(),
						SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
			} else {
				trigger = scheduleCreator.createSimpleTrigger(
				        jobInfo.getJobName(), 
				        new Date(),
				        jobInfo.getRepeatTime(), 
				    
    SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
			}
			scheduler.scheduleJob(jobDetail, trigger);
			jobInfo.setJobStatus("SCHEDULED");
			schedulerRepository.save(jobInfo);
			log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " scheduled.");
		} else {
			log.error("scheduleNewJobRequest.jobAlreadyExist");
		}
	} catch (ClassNotFoundException e) {
		log.error("Class Not Found - {}", jobInfo.getJobClass(), e);
	} catch (SchedulerException e) {
		log.error(e.getMessage(), e);
	}
}

При создании триггера мы передаем MISFIRE_INSTRUCTION . Иногда Кварц может пропустить увольнение с определенной работы. Это может произойти, если рабочие потоки заняты, если планировщик не работает или если в прошлом планировалось выполнение задания, среди прочих подобных проблем.

Мы установили наши триггеры на MISFIRE_INSTRUCTION_FIRE_NOW – который срабатывает снова, если происходит осечка. Если не определено MISFIRE_INSTRUCTION , Quartz принимает Интеллектуальную политикуИНСТРУКЦИЯ _ _MISFIRE _ _ УМНАЯ_ПОЛИТИКА .

Редактирование задания Quartz

Для редактирования заданий мы можем использовать почти тот же метод, что и для их создания, однако мы должны сообщить Планировщику о переносе задания, как только его инструкции будут обновлены:

private void updateScheduleJob(SchedulerJobInfo jobInfo) {
	Trigger newTrigger;
	if (jobInfo.getCronJob()) {
	
		newTrigger = scheduleCreator.createCronTrigger(
		        jobInfo.getJobName(), 
		        new Date(), 
		        jobInfo.getCronExpression(), 
		        simpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
	} else {
	
		newTrigger = scheduleCreator.createSimpleTrigger(
		        jobInfo.getJobName(), 
		        new Date(), 
		        jobInfo.getRepeatTime(),
			    SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
	}
	try {
		schedulerFactoryBean.getScheduler().rescheduleJob(TriggerKey.triggerKey(jobInfo.getJobName()), newTrigger);
		jobInfo.setJobStatus("EDITED & SCHEDULED");
		schedulerRepository.save(jobInfo);
		log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " updated and scheduled.");
	} catch (SchedulerException e) {
		log.error(e.getMessage(), e);
	}
}
Выполните задание Quartz Один раз

Иногда вам хотелось бы нажать на спусковой крючок в специальной ситуации. Вы также можете захотеть уволить работу, чтобы проверить, работает ли она нормально или нет, прежде чем придерживаться расписания.

Мы можем использовать метод trigger Job () , чтобы запустить его немедленно, не дожидаясь запланированного времени или времени. Это позволяет нам создать горячую клавишу тестирования:

public boolean startJobNow(SchedulerJobInfo jobInfo) {
    try {
        SchedulerJobInfo getJobInfo = schedulerRepository.findByJobName(jobInfo.getJobName());
        getJobInfo.setJobStatus("SCHEDULED & STARTED");
        schedulerRepository.save(getJobInfo);
        schedulerFactoryBean.getScheduler().triggerJob(new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
        log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " scheduled and started now.");
        return true;
    } catch (SchedulerException e) {
        log.error("Failed to start new job - {}", jobInfo.getJobName(), e);
        return false;
    }
}
Приостановите работу с кварцем

Если вы хотите приостановить выполнение задания Cron или простого задания , мы можем использовать метод приостановить задание () , который приостановит задание до тех пор, пока вы его не возобновите:

public boolean pauseJob(SchedulerJobInfo jobInfo) {
    try {
        SchedulerJobInfo getJobInfo = schedulerRepository.findByJobName(jobInfo.getJobName());
     	getJobInfo.setJobStatus("PAUSED");
        schedulerRepository.save(getJobInfo);
        schedulerFactoryBean.getScheduler().pauseJob(new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
      log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " paused.");
        return true;
    } catch (SchedulerException e) {
        log.error("Failed to pause job - {}", jobInfo.getJobName(), e);
        return false;
    }
}
Возобновите работу с Кварцем

Естественно, мы можем возобновить приостановленную работу, просто используя метод resume Job() :

public boolean resumeJob(SchedulerJobInfo jobInfo) {
    try {
      SchedulerJobInfo getJobInfo = schedulerRepository.findByJobName(jobInfo.getJobName());
      getJobInfo.setJobStatus("RESUMED");
      schedulerRepository.save(getJobInfo);
      schedulerFactoryBean.getScheduler().resumeJob(new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
      log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " resumed.");
      return true;
    } catch (SchedulerException e) {
      log.error("Failed to resume job - {}", jobInfo.getJobName(), e);
      return false;
    }
}
Удаление задания Quartz

Наконец, мы можем удалить задание, вызвав метод delete Job() :

public boolean deleteJob(SchedulerJobInfo jobInfo) {
    try {
        SchedulerJobInfo getJobInfo = schedulerRepository.findByJobName(jobInfo.getJobName());
        schedulerRepository.delete(getJobInfo);
        log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " deleted.");
        return schedulerFactoryBean.getScheduler().deleteJob(new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
    } catch (SchedulerException e) {
      log.error("Failed to delete job - {}", jobInfo.getJobName(), e);
      return false;
    }
}

Пользовательский интерфейс консоли управления Кварцем

Теперь у нас есть все функциональные возможности, необходимые для объединения нашей Консоли управления Quartz с пользовательским интерфейсом веб-приложения, где мы можем протестировать функции.

Примечание: Пользовательский интерфейс этого приложения предназначен для демонстрации управления жизненным циклом планировщика, а пользовательские интерфейсы гораздо более изменчивы, чем серверная часть. Из-за этого мы не будем уделять много внимания его реализации. Тем не менее, вы можете получить доступ к полному коду интерфейса в нашем репозитории GitHub .

Любой REST API, который запускает методы, которые мы определили ранее, будет работать просто отлично. Наша реализация использует Thymeleaf в качестве механизма рендеринга.

Если вы хотите узнать больше о Thymeleaf, прочитайте “Начало работы с Thymeleaf на Java и Spring”.

Если вы хотите узнать больше о создании REST API, прочитайте наше руководство по созданию REST API с помощью Spring Boot .

Как только вы запустите свое приложение, давайте перейдем к http://localhost:8080/index , чтобы увидеть панель мониторинга.

Во-первых, давайте выберем кнопку Создать , чтобы создать новое задание. Он откроет всплывающее окно и предложит нам заполнить данные о задании.

Давайте создадим задание Cron и Простое задание:

Мы можем видеть все добавленные вакансии в Магазине вакансий:

Вы также можете просматривать журналы заданий – когда задания запускаются одно за другим в соответствии с их критериями запуска.

Вывод

В этом руководстве мы познакомились с Quartz – мощным планировщиком и внедрили его в приложение Spring Boot.

Мы рассмотрели общее управление жизненным циклом планировщика Quartz с демонстрацией в упрощенном пользовательском интерфейсе. Мы использовали некоторые минималистичные задания, но вы можете попробовать определить сложные задания, такие как оповещения о пожаре по электронной почте или асинхронная обработка сообщений и т. Д., И запланировать их с помощью Quartz.

Как всегда, вы можете найти полный исходный код на GitHub .