Запустить задание @Scheduled только на одном узле кластера WebLogic? - PullRequest
13 голосов
/ 16 января 2012

Мы запускаем веб-приложение Spring 3.0.x (.war) с ночным заданием @Scheduled в кластерной среде WebLogic 10.3.4.Однако, поскольку приложение развертывается на каждом узле (с помощью мастера развертывания в веб-консоли AdminServer), задание запускается на каждом узле каждую ночь, поэтому выполняется несколько раз одновременно.

Как мы можем предотвратитьэто случилось?

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

Пожалуйста, дайте мне знать, если есть какие-либо открытые вопросы.Я также задавал этот вопрос на форумах Spring Community .Большое спасибо за вашу помощь.

Ответы [ 8 ]

5 голосов
/ 20 февраля 2013

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

private boolean isTriggerNode() {
   String triggerHostmame = System.getProperty("trigger.hostname");;
   String hostName = InetAddress.getLocalHost().getHostName();
   return hostName.equals(triggerHostmame);
}

public void execute() {
   if (isTriggerNode()) {
      //send email
   }
}
3 голосов
/ 02 января 2015

Я решил эту проблему, сделав один из ящиков мастером.в основном установите переменную окружения на одном из полей, например master = true.

, и прочитайте ее в своем коде Java через system.getenv ("master").если он присутствует и имеет значение true, запустите ваш код.

базовый фрагмент

@schedule()
void process(){
boolean master=Boolean.parseBoolean(system.getenv("master"));
if(master)
{
   //your logic
}

}
3 голосов
/ 31 мая 2013

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

Лучше всего выполнить следующие шаги в одной транзакции с БД: - прочитать значение в таблице общих блокировок - если ни у какого другого узла нет блокировки, взять блокировку - обновить таблицу, указав, что вы берете блокировку

3 голосов
/ 24 января 2012

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

0 голосов
/ 15 июля 2018

Вам не нужно синхронизировать вашу работу, начните использовать БД. В приложении weblogic вы можете получить имя экземпляра, где запущено приложение:

String serverName = System.getProperty("weblogic.Name");

Проще говоря, условие два выполняет задание:

if (serverName.equals(".....")) {
  execute my job;
}

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

0 голосов
/ 11 июля 2018

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

@Scheduled(cron = "59 59 8 * * *" /* Every day at 8:59:59am */)
@TryLock(name = "emailLock", owner = NODE_NAME, lockFor = TEN_MINUTE)
public void sendEmails() {
  List<Email> emails = emailDAO.getEmails();
  emails.forEach(email -> sendEmail(email));
}

См. Мой пост в блоге об его использовании.

0 голосов
/ 04 января 2015

Мы можем заставить другие машины в кластере не запускать пакетное задание, используя следующую строку cron. Он не будет работать до 2099 года.

0 0 0 1 1? 2099

0 голосов
/ 26 февраля 2014

вы можете попробовать использовать TimerManager (планировщик заданий в кластерной среде) из WebLogic в качестве реализации TaskScheduler (TimerManagerTaskScheduler).Он должен работать в кластерной среде.

Андреа

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...