Intereting Posts
Переключение Java-версии за сеанс Случайно удалил папку Нет записи grub для Windows 7 после установки maverick Что делает наутилус? Как сделать поиск штрихов за пределами домашней папки Ubuntu 12.04 LTS ati / amd драйвер не может установить Как получить список открытых файлов / экземпляров в настоящее время в списке быстрого запуска launcher? Специальная сеть (горячая точка), созданная в Ubuntu, не обнаружена телефоном Android Ошибка двойной загрузки EFI: «недействительная арка независимая маска ELF» apt-get upgrade: Сегментация неисправного дерева … 50% Как получить драйверы NVIDIA GeForce GT 210, работающие на Lucid Lynx? Как повторно использовать Unity 3D после установки Bumblebee? ОШИБКА 1045 (28000): Доступ запрещен для пользователя 'root' @ 'localhost' (с использованием пароля: YES) Как установить пользовательские сочетания клавиш с терминала? Могу ли я настроить сетевой интерфейс (eth0, eth1 и т. Д.) По умолчанию, но по-прежнему доступен?

Предотвращение дублирования скрипта в момент времени

Я использую scrapy для получения некоторых ресурсов, и я хочу сделать это как задание cron которое может начинаться каждые 30 минут.

Cron:

 0,30 * * * * /home/us/jobs/run_scrapy.sh` 

run_scrapy.sh:

 #!/bin/sh cd ~/spiders/goods PATH=$PATH:/usr/local/bin export PATH pkill -f $(pgrep run_scrapy.sh | grep -v $$) sleep 2s scrapy crawl good 

Как показано в сценарии, я пытался убить процесс скрипта и дочерний процесс (scrapy).

Однако, когда я пытался запустить два сценария, новый экземпляр скрипта не убивает старый экземпляр.

Как это исправить?


Обновить:

У меня более одного сценария scsh, который работает с разной частотой, настроенной в cron .


Обновление 2 – Тест для ответа Serg :

Все задания cron были остановлены до запуска теста.

Затем я открываю три окна терминала, они называются w1 w2 и w3 и запускают команды в следующих порядках:

 Run `pgrep scrapy` in w3, which print none.(means no scrapy running at the moment). Run `./scrapy_wrapper.sh` in w1 Run `pgrep scrapy` in w3 which print one process id say it is `1234`(means scrapy have been started by the script) Run `./scrapy_wrapper.sh` in w2 #check the w1 and found the script have been terminated. Run `pgrep scrapy` in w3 which print two process id `1234` and `5678` Press `Ctrl+C` in w2(twice) Run `pgrep scrapy` in w3 which print one process id `1234` (means scrapy of `5678` have been stopped) 

В этот момент мне нужно использовать pkill scrapy чтобы прекратить лечение с помощью id 1234

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

 #!/bin/bash # This is /home/user/bin/wrapper.sh file pkill -f 'main_script.sh' exec bash ./main_script.sh 

Конечно, обертка должна быть названа по-разному. Таким образом, pkill может искать только ваш основной скрипт. Таким образом, ваш основной сценарий сводится к следующему:

 #!/bin/sh cd /home/user/spiders/goods PATH=$PATH:/usr/local/bin export PATH scrapy crawl good 

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

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

введите описание изображения здесь

Ваш скрипт

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

Запись cron должна выглядеть так:

 0,30 * * * * /home/us/jobs/scrapy_wrapper.sh 

Содержание scrapy_wrapper.sh

 #!/bin/bash pkill -f 'run_scrapy.sh' exec sh /home/us/jobs/run_scrapy.sh 

Содержание run_scrapy.sh

 #!/bin/bash cd /home/user/spiders/goods PATH=$PATH:/usr/local/bin export PATH # sleep delay now is not necessary # but uncomment if you think it is # sleep 2 scrapy crawl good 

Возможно, вам стоит следить за запуском скрипта, создав файл pid родительского shell-скрипта и попытаться убить предыдущий исполняемый родительский скрипт оболочки, проверив файл pid. Что-то вроде того

 #!/bin/sh PATH=$PATH:/usr/local/bin PIDFILE=/var/run/scrappy.pid TIMEOUT="10s" #Check if script pid file exists and kill process if [ -f "$PIDFILE" ] then PID=$(cat $PIDFILE) #Check if process id is valid ps -p $PID >/dev/null 2>&1 if [ "$?" -eq "0" ] then #If it is valid kill process id kill "$PID" #Wait for timeout sleep "$TIMEOUT" #Check if process is still running after timeout ps -p $PID >/dev/null 2>&1 if [ "$?" -eq "0" ] then echo "ERROR: Process is still running" exit 1 fi fi fi #Create PID file echo $$ > $PIDFILE if [ "$?" -ne "0" ] then echo "ERROR: Could not create PID file" exit 1 fi export PATH cd ~/spiders/goods scrapy crawl good #Delete PID file rm "$PIDFILE" 

Если я понимаю, что вы делаете правильно, вы хотите вызвать процесс каждые 30 минут (через cron). Однако, когда вы запускаете новый процесс через cron, вы хотите убить все существующие версии, все еще запущенные?

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

Это заставит ваш скрипт выглядеть так:

 #!/bin/sh cd ~/spiders/goods PATH=$PATH:/usr/local/bin export PATH timeout 30m scrapy crawl good 

обратите внимание, что таймаут добавлен в последнюю строку

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

Обратите внимание: если вы измените интервал появления в crontab, вам также придется отредактировать скрипт

Поскольку pkill завершает только указанный процесс, мы должны прекратить его дочерние подпроцессы с использованием опции -P . Таким образом, модифицированный скрипт будет выглядеть так:

 #!/bin/sh cd /home/USERNAME/spiders/goods PATH=$PATH:/usr/local/bin export PATH PID=$(pgrep -o run_scrapy.sh) if [ $$ -ne $PID ] ; then pkill -P $PID ; sleep 2s ; fi scrapy crawl good 

trap запускает определенную команду (в двойных кавычках) в событии EXIT , т. е. когда run_scrapy.sh завершается. Есть и другие события, вы найдете их в help trap .
pgrep -o находит самый старый экземпляр процесса с заданным именем.

PS Ваша идея с grep -v $$ хороша, но она не вернет вам PID другого экземпляра run_scrapy.sh , потому что $$ будет PID подпроцесса $(pgrep run_scrapy.sh | grep -v $$) , а не PID run_scrapy.sh который запустил его. Вот почему я использовал другой подход.
PPS. Здесь вы найдете несколько других методов завершения подпроцессов в Bash.

Ну, у меня была аналогичная проблема с C с использованием popen () и хотелось убить после тайм-аута родителя и всех дочерних элементов. трюк задает идентификатор группы процессов, когда вы начинаете свой родитель, чтобы не убить себя. как это сделать можно прочитать здесь: https://stackoverflow.com/questions/6549663/how-to-set-process-group-of-a-shell-script с "ps -eo pid, ppid, cmd, etime «вы можете фильтровать по времени выполнения. поэтому с обеих данных вы должны иметь возможность фильтровать все старые процессы и убивать их.

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

 if "$SSS" = "Idle" then set $SSS=Running" your script set $SSS="Idle" 

Вы также можете отслеживать состояние, создавая / проверяя / удаляя файл маркера, например touch /pathname/myscript.is.running и используя, если существуют при запуске, и rm /pathname/myscript.is.running в конце.

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

Независимо от того, как вы отслеживаете статус вашего скрипта и имеете ли вы решение проблемы, предотвращая запуск или убивая текущий процесс, я считаю, что использование сценария оболочки, предложенного @JacobVlijm & @Serg, сделает вашу жизнь намного проще.