Источник: https://github.com/lukas-krecan/ShedLock
Краткое описание
ShedLock — Java библиотека — надстройка над Spring scheduled, которая позволяет засинхронизировать работу подов через таблицу в БД
ShedLock гарантирует, что ваши запланированные задачи будут выполняться не более одного раза в одно и то же время. Если задача выполняется на одном узле, она получает блокировку, которая предотвращает выполнение той же задачи с другого узла (или потока). Обратите внимание, что если одна задача уже выполняется на одном узле, выполнение на других узлах не ждет, оно просто пропускается.
ShedLock предназначен для использования в ситуациях, когда у вас есть запланированные задачи, которые не готовы к параллельному выполнению, но могут безопасно выполняться повторно. ShedLock предполагает, что часы на узлах синхронизированы, так как блокировки основаны на времени
Максимально допустимая к использованию версия при использовании JDK 11 — version 4.44.0
Основная информация
Postgres Свернуть исходный код
# Postgres CREATE TABLE shedlock( name VARCHAR (64) NOT NULL , lock_until TIMESTAMP NOT NULL , locked_at TIMESTAMP NOT NULL , locked_by VARCHAR (255) NOT NULL , PRIMARY KEY ( name )); |
pom.xml Свернуть исходный код
< dependency > < groupId >net.javacrumbs.shedlock</ groupId > < artifactId >shedlock-spring</ artifactId > < version >4.42.0</ version > </ dependency > < dependency > < groupId >net.javacrumbs.shedlock</ groupId > < artifactId >shedlock-provider-jdbc-template</ artifactId > < version >4.42.0</ version > </ dependency > |
Указав usingDbTime(), поставщик блокировки будет использовать время UTC на основе часов сервера БД. Если вы не укажете эту опцию, будут использоваться часы с сервера приложений (часы на серверах приложений могут быть не синхронизированы, что приведет к различным проблемам с блокировкой).
Для блокировки ShedLock использует Spring AOP, соответственно классы с блокируемыми методами должны иметь аннотацию EnableSchedulerLock, а сами методы SchedulerLock
@SchedulerLock(name = «scheduledTaskName»)
- Блокируются только аннотированные методы, все остальные запланированные задачи библиотека игнорирует
- Имя для блокировки. Одновременно может выполняться только одна задача с одинаковым именем.
атрибут lockAtMostFor, который указывает, как долго должна сохраняться блокировка в случае смерти исполняющего узла. Это всего лишь запасной вариант, при нормальных обстоятельствах блокировка снимается, как только задачи завершаются. Вы должны установить для lockAtMostFor значение, которое намного больше, чем обычное время выполнения. Если задача занимает больше времени, чем lockAtMostFor, результирующее поведение может быть непредсказуемым (более чем один процесс будет эффективно удерживать блокировку). Если вы не укажете lockAtMostFor в @SchedulerLock, будет использоваться значение по умолчанию из @EnableSchedulerLock.
Наконец, вы можете установить атрибут lockAtLeastFor, который указывает минимальное количество времени, в течение которого должна сохраняться блокировка. Его основная цель — предотвратить выполнение с нескольких узлов в случае очень коротких задач и разницы в часах между узлами.
Установив lockAtMostFor, мы гарантируем, что блокировка будет снята, даже если узел умрет, а установив lockAtLeastFor, мы удостоверимся, что она не выполняется более одного раза в пятнадцать минут.
Не удаляйте вручную строку блокировки из таблицы БД. ShedLock имеет в памяти кэш существующих строк блокировки, поэтому строка НЕ будет автоматически воссоздана до перезапуска приложения. Если вам нужно, вы можете отредактировать строку
Режимы интеграции Spring
PROXY_METHOD — Начиная с версии 4.0.0 Spring AOP по умолчанию — это прокси-сервер AOP вокруг аннотированного метода.
PROXY_SCHEDULER
Мы используем только PROXY_METHOD
@Scheduled(fixedDelayString = "${autoload.pollDelay}")
@SchedulerLock(name = "TaskScheduler_autoLoadV1",
lockAtLeastFor = "${autoload.lockAtLeastFor}", lockAtMostFor = "${autoload.lockAtMostFor}")
public void autoUpdate() {
String date = DateUtils.formatDate(LocalDate.now());
update(date);
}
Недостатком является то, что блокировка применяется, даже если вы вызываете метод напрямую. Final и non-public методы не проксируются
