Предотвращение дублирования заданий cron

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

Чтобы решить проблему, я заставил скрипт искать существование определенного файла (« lockfile.txt ») и выйти, если он существует, или touch, если он не делает. Но это довольно паршивый семафор! Есть ли лучшая практика, о которой я должен знать? Должен ли я написать демона вместо этого?

79 голосов | спросил Tom 9 12009vEurope/Moscow11bEurope/MoscowMon, 09 Nov 2009 14:32:18 +0300 2009, 14:32:18

9 ответов


105

Существует несколько программ, которые автоматизируют эту функцию, отнимают от этого раздражение и потенциальные ошибки, а также избегают проблемы с устаревшей блокировкой, используя стаю за кулисами (что является риском, если вы просто используя touch). Я использовал lockrun и lckdo в прошлом, но теперь есть flock (1) (в новых версиях util-linux), который Великий. Это очень просто:

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job
ответил womble 9 12009vEurope/Moscow11bEurope/MoscowMon, 09 Nov 2009 14:57:07 +0300 2009, 14:57:07
27

Лучший способ в оболочке - использовать flock (1)

(
  flock -x -w 5 99
  ## Do your stuff here
) 99>/path/to/my.lock
ответил Philip Reynolds 9 12009vEurope/Moscow11bEurope/MoscowMon, 09 Nov 2009 14:45:05 +0300 2009, 14:45:05
21

Собственно, flock -n может использоваться вместо lckdo *, поэтому вы будете использовать код от разработчиков ядра.

На основе примера womble вы должны написать что-то вроде:

* * * * * flock -n /some/lockfile command_to_run_every_minute

Кстати, глядя на код, все flock, lockrun и lckdo делают то же самое, так что это всего лишь вопрос из которых наиболее легко доступны вам.

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

ответил Amir 20 52009vEurope/Moscow11bEurope/MoscowFri, 20 Nov 2009 01:43:29 +0300 2009, 01:43:29
2

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

Lockfiles используются initscripts и многими другими приложениями и утилитами в Unix-системах.

ответил Born To Ride 9 12009vEurope/Moscow11bEurope/MoscowMon, 09 Nov 2009 14:36:15 +0300 2009, 14:36:15
1

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

ответил 9 12009vEurope/Moscow11bEurope/MoscowMon, 09 Nov 2009 14:45:56 +0300 2009, 14:45:56
1

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

Итак, если вы хотите зависеть от lckdo или подобного, вы можете сделать это:


PIDFILE=/tmp/`basename $0`.pid

if [ -f $PIDFILE ]; then
  if ps -p `cat $PIDFILE` > /dev/null 2>&1; then
      echo "$0 already running!"
      exit
  fi
fi
echo $$ > $PIDFILE

trap 'rm -f "$PIDFILE" >/dev/null 2>&1' EXIT HUP KILL INT QUIT TERM

# do the work

ответил Aleksandar Ivanisevic 9 12009vEurope/Moscow11bEurope/MoscowMon, 09 Nov 2009 17:33:04 +0300 2009, 17:33:04
1

Ваш демон cron не должен вызывать задания, если предыдущие экземпляры их все еще запущены. Я разработчик одного демона cron dcron , и мы специально пытаемся предотвратить это , Я не знаю, как справляются с этим Vixie cron или другими демонами.

ответил dubiousjim 17 FebruaryEurope/MoscowbWed, 17 Feb 2010 18:59:08 +0300000000pmWed, 17 Feb 2010 18:59:08 +030010 2010, 18:59:08
1

Я бы рекомендовал использовать run-one команда - намного проще, чем иметь дело с замками. Из документов:

run-one - это сценарий оболочки, который содержит не более одного уникального экземпляра некоторой команды с уникальным набором аргументов. Это часто полезно для cronjobs, если вы хотите, чтобы одновременно выполнялось не более одной копии.

run-this-one похож на run-one, за исключением того, что он будет использовать pgrep и kill для поиска и уничтожения любых запущенных процессов, принадлежащих пользователю и сопоставление целевых команд и аргументов. Обратите внимание, что run-this-one будет блокироваться при попытке убить соответствующие процессы, пока все совпадения процессы мертвы.

run-one-constant работает точно так же, как и run-one, за исключением того, что он respawns "COMMAND [ARGS]" в любое время, когда COMMAND выходит (ноль или ненулевое значение).

keep-one-running - это псевдоним для запуска-один-постоянно.

run-one-until-success работает точно так же, как run-one-always, кроме что он обновляет команду «COMMAND [ARGS]» до тех пор, пока COMMAND не выйдет успешно (то есть, выходит из нуля).

run-one-until-failure работает точно так же, как run-one-always, кроме что он возрождает «COMMAND [ARGS]», пока COMMAND не выйдет с ошибкой (т. е. выходит за пределы нуля).

ответил Yurik 3 +03002017-10-03T00:53:04+03:00312017bEurope/MoscowTue, 03 Oct 2017 00:53:04 +0300 2017, 00:53:04
0

Я создал одну банку для решения такой проблемы, как запуск повторяющихся кронов, может быть java или shell cron. Просто передайте имя cron в Duplicates.CloseSessions ("Demo.jar"), это будет искать и убивать существующий pid для этого cron, кроме текущего. Я реализовал метод для этого. String proname = ManagementFactory.getRuntimeMXBean (). GetName ();                 String pid = proname.split ("@") [0];                 System.out.println («Текущий PID:» + pid);

            Process proc = Runtime.getRuntime().exec(new String[]{"bash","-c"," ps aux | grep "+cronname+" | awk '{print $2}' "});

            BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            String s = null;
            String killid="";

            while ((s = stdInput.readLine()) != null ) {                                        
                if(s.equals(pid)==false)
                {
                    killid=killid+s+" ";    
                }
            }

И затем убить killid string с помощью команды shell

ответил Sachin Patil 28 WedEurope/Moscow2016-12-28T11:36:01+03:00Europe/Moscow12bEurope/MoscowWed, 28 Dec 2016 11:36:01 +0300 2016, 11:36:01

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132