Перейти к основному содержимому

Фоновые задания весной с JobRunr

· 5 мин. чтения

1. Обзор

В этом руководстве мы рассмотрим распределенное планирование и обработку фоновых заданий в Java с помощью JobRunr и интегрируем его со Spring.

2. О JobRunr

JobRunr — это библиотека, которую мы можем встроить в наше приложение и которая позволяет нам планировать фоновые задания с помощью лямбда-выражения Java 8. Мы можем использовать любой существующий метод наших сервисов Spring для создания задания без необходимости реализации интерфейса. Задание может быть коротким или длительным процессом, и оно будет автоматически перенесено в фоновый поток, чтобы текущий веб-запрос не блокировался.

Для выполнения своей работы JobRunr анализирует лямбду Java 8. Он сериализует его как JSON и сохраняет либо в реляционной базе данных, либо в хранилище данных NoSQL.

3. Возможности JobRunr

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

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

4. Настройка

Для простоты мы будем использовать хранилище данных в памяти для хранения всей информации, связанной с работой.

4.1. Конфигурация Maven

Давайте сразу перейдем к коду Java. Но перед этим нам нужно объявить следующую зависимость Maven в нашем файле pom.xml :

<dependency>
<groupId>org.jobrunr</groupId>
<artifactId>jobrunr-spring-boot-starter</artifactId>
<version>3.1.2</version>
</dependency>

4.2. Весенняя интеграция

Прежде чем мы перейдем непосредственно к созданию фоновых заданий, нам нужно инициализировать JobRunr. Поскольку мы используем зависимость jobrunr-spring-boot-starter , это легко сделать. Нам нужно только добавить некоторые свойства в application.properties :

org.jobrunr.background-job-server.enabled=true
org.jobrunr.dashboard.enabled=true

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

По умолчанию jobrunr-spring-boot-starter попытается использовать ваш существующий источник данных в случае реляционной базы данных для хранения всей информации, связанной с заданием.

Однако, поскольку мы будем использовать хранилище данных в памяти, нам необходимо предоставить bean-компонент StorageProvider :

@Bean
public StorageProvider storageProvider(JobMapper jobMapper) {
InMemoryStorageProvider storageProvider = new InMemoryStorageProvider();
storageProvider.setJobMapper(jobMapper);
return storageProvider;
}

5. Использование

Теперь давайте узнаем, как создавать и планировать фоновые задания в Spring с помощью JobRunr.

5.1. Внедрить зависимости

Когда мы хотим создавать задания, нам нужно внедрить JobScheduler и нашу существующую службу Spring, содержащую метод, для которого мы хотим создать задания, в данном случае SampleJobService :

@Inject
private JobScheduler jobScheduler;

@Inject
private SampleJobService sampleJobService;

Класс JobScheduler из JobRunr позволяет нам ставить в очередь или планировать новые фоновые задания.

SampleJobService может быть любой из наших существующих служб Spring, содержащей метод, обработка которого в веб-запросе может занять слишком много времени. Это также может быть метод, который вызывает некоторые другие внешние службы, которым мы хотим добавить устойчивость, поскольку JobRunr повторит попытку метода в случае возникновения исключения.

5.2. Создание заданий типа «выстрелил-забыл»

Теперь, когда у нас есть зависимости, мы можем создавать задания типа «запустил и забыл», используя метод постановки в очередь :

jobScheduler.enqueue(() -> sampleJobService.executeSampleJob());

Задания могут иметь параметры, как и любая другая лямбда:

jobScheduler.enqueue(() -> sampleJobService.executeSampleJob("some string"));

Эта строка гарантирует, что лямбда-выражение, включая тип, метод и аргументы, будет сериализовано в виде JSON в постоянное хранилище (СУБД, такая как Oracle, Postgres, MySql и MariaDB, или база данных NoSQL).

Выделенный рабочий пул потоков, запущенных во всех различных BackgroundJobServer , затем выполнит эти поставленные в очередь фоновые задания как можно скорее в порядке «первым поступил — первым обслужен». JobRunr гарантирует выполнение вашей работы одним работником посредством оптимистической блокировки.

5.3. Планирование работы в будущем

Мы также можем планировать задания в будущем, используя метод schedule :

jobScheduler.schedule(LocalDateTime.now().plusHours(5), () -> sampleJobService.executeSampleJob());

5.4. Повторное планирование заданий

Если мы хотим иметь повторяющиеся задания, нам нужно использовать метод scheduleRecurrently :

jobScheduler.scheduleRecurrently(Cron.hourly(), () -> sampleJobService.executeSampleJob());

5.5. Аннотирование с помощью аннотации @Job

Чтобы контролировать все аспекты задания, мы можем аннотировать наш сервисный метод аннотацией @Job . Это позволяет установить отображаемое имя на панели управления и настроить количество повторных попыток в случае сбоя задания.

@Job(name = "The sample job with variable %0", retries = 2)
public void executeSampleJob(String variable) {
...
}

Мы даже можем использовать переменные, которые передаются нашему заданию в отображаемом имени с помощью синтаксиса String.format() .

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

6. Панель управления

JobRunr поставляется со встроенной панелью инструментов, которая позволяет нам отслеживать нашу работу. Мы можем найти его по адресу http://localhost:8000 и проверить все задания, включая все повторяющиеся задания, и оценить, сколько времени потребуется, чтобы обработать все поставленные в очередь задания:

./a34e84637eda542ee27768cae7f49e9d.png

Могут случиться плохие вещи, например, срок действия SSL-сертификата истек, или диск переполнен. JobRunr по умолчанию перепланирует фоновое задание с экспоненциальной политикой отсрочки. Если фоновое задание продолжает сбой десять раз, только тогда оно перейдет в состояние « Ошибка » . Затем вы можете решить повторно поставить невыполненное задание в очередь, когда основная причина будет устранена.

Все это отображается на панели инструментов, включая каждую повторную попытку с точным сообщением об ошибке и полной трассировкой стека, объясняющей, почему задание не удалось:

./2acd6ba979b33c00b7e4293680a49051.png

7. Заключение

В этой статье мы создали наш первый базовый планировщик, используя JobRunr с помощью jobrunr-spring-boot-starter . Ключевым выводом из этого руководства является то, что мы смогли создать задание с помощью всего одной строки кода и без какой-либо конфигурации на основе XML или необходимости реализации интерфейса.

Полный исходный код примера доступен на GitHub .