Предотвратите дублирующийся скрипт, запущенный в sametime

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

Крон:

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

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

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

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


Обновление:

У меня есть больше чем один .sh пестрый сценарий, которые работают на другой частоте, настроенной в cron.


Обновление 2 - тестирует на Sergответ:

Все задания крона были остановлены, прежде чем я запущу тест.

Затем я открываюсь, три окна терминала говорят, что их называют 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 остановиться пестрый с идентификатором 1234

5
задан 10 August 2016 в 17:26

7 ответов

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

#!/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

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

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

enter image description here

Ваш сценарий

, Это - просто пример. Помните, что у меня нет доступа к пестрому для фактического тестирования этого, так скорректируйте это по мере необходимости для ситуации.

Ваша запись крона должна быть похожей на это:

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
9
ответ дан 23 November 2019 в 08:43

Возможно, необходимо контролировать, если сценарий работает путем создания родительского файла 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"
2
ответ дан 23 November 2019 в 08:43

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

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

Это заставило бы Ваш сценарий быть похожим на это:

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

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

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

Примечание, что при изменении интервала икры в crontab необходимо будет отредактировать сценарий также

2
ответ дан 23 November 2019 в 08:43

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

0
ответ дан 23 November 2019 в 08:43

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

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

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

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

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

0
ответ дан 23 November 2019 в 08:43

Как 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 находит самый старый экземпляр процесса с определенным именем.

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

1
ответ дан 23 November 2019 в 08:43

слишком простой :

#!/bin/bash 

pids=($(pidof -x sample.sh))

if [ ${#pids[@]} -gt 1 ] ; then 
                echo "Script already running by pid ${pids[1]}" 
                exit 
fi

echo "Starting service "
sleep 1000
0
ответ дан 27 May 2020 в 11:27

Другие вопросы по тегам:

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