1. Обзор
Spring предоставляет простой в реализации API для планирования заданий. Он отлично работает до тех пор, пока мы не развернем несколько экземпляров нашего приложения. Spring по умолчанию не может обрабатывать синхронизацию планировщика в нескольких экземплярах – вместо этого он выполняет задания одновременно на каждом узле.
В этом коротком уроке мы рассмотрим ShedLock – библиотеку Java, которая гарантирует, что наши запланированные задачи выполняются только один раз в одно и то же время и является альтернативой Quartz .
2. Зависимости Maven
Чтобы использовать ShedLock с пружиной, нам нужно добавить //shedlock-spring зависимость :
net.javacrumbs.shedlock shedlock-spring 2.2.0
3. Конфигурация
Обратите внимание, что ShedLock работает только в средах с общей базой данных, объявив правильный Поставщик блокировки . Он создает таблицу или документ в базе данных, где он хранит информацию о текущих блокировках.
В настоящее время ShedLock поддерживает Mongo, Redis, Hazelcast, ZooKeeper и все, что имеет драйвер JDBC.
В этом примере мы будем использовать базу данных H2 в памяти. Чтобы это сработало, нам нужно предоставить базу данных H2 и зависимость Шерлока от JDBC :
net.javacrumbs.shedlock shedlock-provider-jdbc-template 2.1.0 com.h2database h2 1.4.200
Затем нам нужно создать таблицу базы данных для ShedLock, чтобы хранить информацию о блокировках планировщика:
CREATE TABLE shedlock ( name VARCHAR(64), lock_until TIMESTAMP(3) NULL, locked_at TIMESTAMP(3) NULL, locked_by VARCHAR(255), PRIMARY KEY (name) )
Мы должны объявить источник данных в файле свойств нашего приложения Spring Boot, чтобы DataSource bean мог быть Autowired . В этом примере мы используем application.yml для определения источника данных базы данных H2:
spring: datasource: driverClassName: org.h2.Driver url: jdbc:h2:mem:shedlock_DB;INIT=CREATE SCHEMA IF NOT EXISTS shedlock;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE username: sa password:
Давайте сконфигурируем Поставщика блокировки с конфигурацией источника данных выше. Весна может сделать это довольно просто:
@Configuration public class SchedulerConfiguration { @Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider(dataSource); } }
Еще одним требованием к конфигурации, которое мы должны предоставить, являются @EnableScheduling и @EnableSchedulerLock аннотации к нашему классу конфигурации Spring:
@SpringBootApplication @EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "PT30S") public class Application { public static void main(String[] args) { SpringApplication.run(SpringApplication.class, args); } }
Параметр Блокировка по умолчанию Не более чем для указывает время, в течение которого блокировка по умолчанию должна сохраняться в случае смерти исполняющего узла. Он использует формат ISO8601/|.
В следующем разделе мы рассмотрим, как переопределить это значение по умолчанию.
4. Создание Задач
Чтобы создать запланированную задачу, обрабатываемую Шерлоком, мы просто помещаем аннотации @Schedulerlock и @SchedulerLock/| в метод:
@Component class BaeldungTaskScheduler { @Scheduled(cron = "0 0/15 * * * ?") @SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtLeastForString = "PT5M", lockAtMostForString = "PT14M") public void scheduledTask() { // ... } }
Во-первых, давайте посмотрим на @Scheduled . Он поддерживает формат cron , причем это выражение означает “каждые 15 минут”.
Далее, взглянув на @SchedulerLock, параметр name должен быть уникальным, и classname_method name обычно достаточно для этого. Мы не хотим, чтобы одновременно выполнялось более одного запуска этого метода, и для этого ShedLock использует уникальное имя.
Мы также добавили несколько дополнительных параметров.
Во-первых, мы добавили lock, по крайней мере, для строки , чтобы мы могли установить некоторое расстояние между вызовами методов. Использование “PT5M” означает, что этот метод будет удерживать блокировку как минимум в течение 5 минут. Другими словами, это означает, что этот метод может запускаться ShedLock не чаще, чем каждые пять минут.
Затем мы добавили lockAtMostForString , чтобы указать, как долго должна сохраняться блокировка в случае смерти исполняющего узла. Использование “PTM” означает, что он будет заблокирован не более чем на 14 минут.
В обычных ситуациях ShedLock снимает блокировку сразу после завершения задачи. Теперь нам не нужно было этого делать, потому что в @EnableSchedulerLock есть значение по умолчанию, но мы решили переопределить его здесь.
5. Заключение
В этой статье мы узнали, как создавать и синхронизировать запланированные задачи с помощью ShedLock.
Как всегда, весь исходный код доступен на GitHub .