Как автоматически перезапустить скрипт Python, если он был убит или умер

31

Я запускаю свой сценарий Python в фоновом режиме на моем компьютере с Ubuntu (12.04) следующим образом:

nohup python testing.py > test.out &

Теперь может быть возможно, что на каком-то этапе мой выше Python scriptможет умереть по любой причине.

Так что я думаю иметь какой-то cron agentскрипт в bash shell, который может автоматически перезапустить мой вышеописанный скрипт на Python, если он по какой-либо причине будет убит

Возможно ли это сделать? Если да, то как лучше всего решить эту проблему?

ОБНОВИТЬ:

После создания testing.confфайла, как это -

chdir /tekooz
exec python testing.py
respawn

Я запустил команду sudo, чтобы запустить ее, но я не вижу, как этот процесс выполняется с использованием ps ax?

root@bx13:/bezook# sudo start testing
testing start/running, process 27794
root@bx13:/bezook# ps ax | grep testing.py
27806 pts/3    S+     0:00 grep --color=auto testing.py

Есть идеи, почему px axe мне ничего не показывает? И как я могу проверить, работает ли моя программа или нет?

Это мой скрипт на Python -

#!/usr/bin/python
while True:
    print "Hello World"
    time.sleep(5)
арсенал
источник

Ответы:

24

В Ubuntu (до 14.04, 16.04 и позже используйте systemd) можно использовать upstart для этого лучше, чем задание cron. Вы вводите настройки конфигурации /etc/initи убедитесь, что вы задаете респаун

Это может быть минимальный файл /etc/init/testing.conf(отредактируйте как root):

chdir /your/base/directory
exec python testing.py
respawn

И вы можете проверить с /your/base/directory/testing.py:

from __future__ import print_function

import time

with open('/var/tmp/testing.log', 'a') as fp:
    print(time.time(), 'done', file=fp)
    time.sleep(3)

и начать с:

sudo start testing

и следите за тем, что происходит (в другом окне), с помощью:

tail -f /var/tmp/testing.log

и остановитесь на:

sudo stop testing

Вы также можете добавить [start on][2]команду запуска при загрузке системы.

Zelda
источник
Если вы используете задание cron, вам нужно либо внедрить, либо найти какой-то код для надежной обработки PID-файлов. Вы хотите, чтобы ваша служба / script / daemon создала PID-файл (условно расположенный в / var / run) и чтобы его стартовый код проверял, не устарело ли содержимое файла (оставленное уничтоженным процессом). Этот вид кода на удивление трудно написать без рас и угловых случаев. stackoverflow.com/questions/788411/…
Джим Деннис
@Zelda: Спасибо за предложение ... Я новичок в мире Linux / Unix .. Какие изменения я должен внести в /etc/initфайл? Если вы можете предоставить пошаговое руководство для меня, тогда я смогу чему-то научиться и делать правильные вещи ..
Арсенал
@ Вебби Я сделал ответ более полным. Если вы не хотите открывать файл для вывода и переписывать свои операторы печати, вы можете сделать что-то вроде sys.stdout = open(file_name, 'w')в начале.
Зельда
Спасибо, Зельда. Благодарим Вас за помощь. Я обновил вопрос с некоторыми деталями. Я пытаюсь сделать так, чтобы увидеть, запущен ли мой testing.py или нет .. Он не показывает мне, работает он или нет .. px ax | grep testing.py.. Он мне ничего не возвращает? Есть идеи почему?
Арсенал
Вы должны поместить все это в предложение try / исключением и записать в файл журнала, какое исключение было сгенерировано и что программа закрывается. Возможно, оператор print не работает, так как не может записать в stdout.
Зельда
20

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

  1. Создайте новый crontab, запустив crontab -e. Откроется окно вашего любимого текстового редактора.

  2. Добавьте эту строку в файл, который только что открылся

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
  3. Сохраните файл и выйдите из редактора.

Вы только что создали новый, crontabкоторый будет запускаться каждые 5 минут и запускать ваш скрипт, если он еще не запущен. Смотрите здесь для милого небольшого урока cron. Официальные документы по Ubuntu cronнаходятся здесь .

Фактическая команда, pgrepкоторая выполняется, выполняет поиск запущенных процессов для строки, заданной в командной строке. pgrep fooбудет искать названную программу fooи вернуть ее идентификатор процесса . pgrep -fпозволяет выполнять поиск по всей командной строке, используемой для запуска программы, а не только по имени программы (полезно, потому что это скрипт на python).

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

Тердон
источник
Спасибо .. Но я новичок в Linux и Unix, так что не знаете, где находится crontab? Это файл в моей машине с Ubuntu?
Арсенал
@ Вебби смотри обновленный ответ.
Terdon
Спасибо Terdon .. Я могу запустить эту команду crontab -eиз каталога, где мой скрипт Python .. Правильно?
Арсенал
1
@ Вебби, вы можете запустить его где угодно. cronэто демон планирования, это служба, которая работает в фоновом режиме. Если ваш скрипт на python отсутствует $PATH(если вы не можете запустить его из любого места, но вам нужно находиться в его каталоге), используйте полный путь к скрипту, как в моем обновленном ответе.
Тердон
Спасибо. Теперь это имеет смысл ... Я только что создал новый crontab и отредактировал файл, добавив одну и ту же строку, но в течение 1 минуты ... Я уже создал скрипт Hello World Python, вращающийся вокруг, в то время как True назван test.py .. После сохранения файл crontab, он должен автоматически запускать testing.py через 1 минуту? И затем продолжайте проверять каждую минуту, работает ли скрипт Python или нет? Если да, после сохранения файла crontab -e я сделал ps ax | grep testing.py и я не могу увидеть какой-либо процесс для этого?
Арсенал
6

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

import subprocess

while True:
    try:
        print subprocess.check_output(['python', 'testing.py'])
    except KeyboardInterrupt:
        break

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

Энтон
источник
6

Вы не должны действительно использовать это для производства, но вы могли бы:

#!/bin/sh

while true; do
  nohup python testing.py >> test.out
done &

Если по какой-либо причине процесс python завершается, цикл оболочки продолжится и перезапустит его, добавив его в .outфайл по желанию. Почти нет накладных расходов и занимает очень мало времени на настройку.

K3 --- СРН
источник
6

Существует несколько способов мониторинга и повторного запуска процессов в UNIX / Linux. Одна из самых старых - это запись "респавна" в / etc / inittab ... если вы используете старую систему инициализации SysV. Другой метод - использовать демон supervisor из пакета daemontools DJ Bernstein . Другие варианты - использовать функции в Ubuntu Upstart ... или Systemd или других.

Но вы можете посмотреть на альтернативы init и в коде Python для Pardus: в частности, mudur daemon.

Если вы решите пойти с заданием cron (и обработкой файла PID), подумайте о том, чтобы прочитать этот PEP 3143 и, возможно, использовать его эталонную реализацию.

Как я упоминал в других моих комментариях, надежная обработка PID-файлов является сложной задачей. Это склонно к гонкам и угловым случаям. Это становится сложнее, если есть какой-либо шанс, что ваш файл PID окажется в NFS или другой сетевой файловой системе (некоторая атомарность гарантирует, что вы получите с семантикой обработки файлов в надлежащих локальных файловых системах UNIX / Linux, которые исчезнут в некоторых версиях и реализациях NFS, например). Также семантика вокруг блокировки файлов в UNIX может быть сложной. (Быстро ли снимается блокировка flockили fcntlблокировка в вашей целевой ОС, например, когда процесс, удерживающий ее, уничтожается с помощью SIGKILL?).

Джим Деннис
источник
3

Вы также можете использовать мониторинг Monit Or Process с помощью ps-watcher.

Monit - это утилита с открытым исходным кодом для управления и мониторинга процессов, программ, файлов, каталогов и файловых систем в системе UNIX. Монит проводит автоматическое обслуживание и ремонт и может выполнять значимые причинно-следственные действия в ситуациях ошибки.

Вот пример для вашего сценария:

check process myprocessname
        matching "myprocessname"
        start program = "nohup /usr/bin/python /path/testing.py > /tmp/test.out &"
        stop program = "/usr/bin/killall myprocessname"

Взгляните на примеры Монит

Рахул Патил
источник
1

Вам нужен руководитель, вы можете использовать руководителя . Это основанный на Python супервизор, поэтому его легко изменить, если вам нужно.

Управление осуществляется с помощью файлов с синтаксисом .ini.

user41123
источник
0

Ответ Тердона не сработал для меня, потому что pgrep -f testing.pyникогда не « терпел неудачу». Было бы получить pid для задания cron (из-за опции -f). Однако без опции -f pgrep не найдет test.py, потому что нет процесса с именем test.py.

Моим решением этого было изменить

pgrep -f testing.py

в

pgrep -f testing.py | pgrep python

это означает, что полная работа crontab будет такой:

*/5 * * * * pgrep -f testing.py | pgrep python || nohup python /home/you/scripts/testing.py > test.out
Matt
источник
0

В моем случае, как быстрое исправление, я хотел, чтобы моя программа работала, когда она выходила с ошибкой en или она была убита. С другой стороны, я хотел остановить выполнение, когда программа завершилась правильно (код возврата = 0)

Я проверил это на Bash. Он должен нормально работать в любой другой оболочке

#!/bin/sh

echo ""
echo "Use: $0 ./instagram.py"
echo ""

echo "Executing $1 ..."

EXIT_CODE=1
(while [ $EXIT_CODE -gt 0 ]; do
    $1
    # loops on error code: greater-than 0
    EXIT_CODE=$?
done)
user9869932
источник
0

Для ответа Тердона, pgrep -f testing.pyникогда не вернется false в соответствии с комментариями здесь :

Я думаю, проблема в том, что cron порождает оболочку для запуска вашей команды, а аргументы этой оболочки совпадают с pgrep, так как вы используете -f

Ответ Мэтта pgrep -f testing.pyбесполезен, поскольку pgrep pythonсоответствует любому запущенному скрипту Python. Так что если два сценария Python cronjob, второй cronjob никогда не запустится.

И тогда я нашел решение, чтобы решить pgrep -f testing.pyв комментарии здесь: https://askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

Мой cron для запуска двух скриптов Python:

* * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript1\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript1.py

0 * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript2\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript2.py
Фрэнк
источник