Як автоматично перезапустити скрипт 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 мені нічого не показує? І як я можу перевірити, чи працює моя програма чи ні?

Це мій сценарій python -

#!/usr/bin/python
while True:
    print "Hello World"
    time.sleep(5)

Відповіді:


24

У Ubuntu (до 14.04, 16.04 і пізніше використовувати systemd) можна скористатись швидкістю, щоб зробити це краще, ніж робота з 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]команду до запуску під час завантаження системи.


Якщо ви використовуєте роботу cron, вам потрібно буде або реалізувати, або знайти якийсь код для надійної обробки файлів PID. Ви хочете, щоб ваша служба / скрипт / демон демонстрували файл PID (звичайно розташований під / var / run) і перевіряли його код запуску, чи вміст файлу несвіжий (залишений вбитим процесом). Такого коду напрочуд складно написати без перегонів та кутових справ. stackoverflow.com/questions/788411/…
Джим Денніс

@ Zelda: Дякую за пропозицію. Я новачок у світі Linux / Unix. Який тип змін я повинен внести у /etc/initфайл? Якщо ви зможете надати покроковий посібник для мене, тоді я зможу чомусь навчитися і робити все правильно ..
арсенал

@Webby Я зробив відповідь більш повною. Якщо ви не хочете відкривати файл для виводу та переписувати свої друковані висловлювання, ви можете зробити щось подібне sys.stdout = open(file_name, 'w')на початку.
Зельда

Дякую, Зельда. Оцінив вашу допомогу .. Я оновив питання з деякими деталями .. Я намагаюся зробити це так, щоб побачити, чи працює мій тест.py чи ні .. Він не показує, працює він чи ні px ax | grep testing.py.. Це мені нічого не повертає? Будь-яка ідея чому?
арсенал

Ви повинні поставити все це у пункті спробу / за винятком пункту та записати у логфайл, яке виключення було створено та що програма виходить. Можливо, операція друку не працює, оскільки не може записати в 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?
арсенал

@Webby бачимо оновлену відповідь.
terdon

Дякую тердон .. Я можу запустити цю команду crontab -eз каталогу, де мій скрипт python .. Правильно?
арсенал

1
@Веббі ви можете запускати його з будь-якого місця. cronце демон планування, це служба, яка працює у фоновому режимі. Якщо ваш скрипт python відсутній у вашому $PATH(якщо ви не можете його запустити з будь-якого місця, але вам потрібно знаходитись у його каталозі), використовуйте повний шлях до сценарію, як у моїй оновленій відповіді.
terdon

Спасибі. Тепер це має сенс. Я щойно створив новий crontab і відредагував файл, додавши той самий єдиний рядок, але протягом 1 хвилини .. Я вже створив Hello World Python скрипт, який обертається в той час, як True названий тестуванням.py .. Після збереження файл crontab, він повинен автоматично запустити test.py через 1 хвилину? А потім продовжуйте перевіряти кожні 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файлу за бажанням. Майже немає накладних витрат і потрібно дуже мало часу для налаштування.


6

Існує ряд способів контролю та відновлення процесів в UNIX / Linux. Однією з найстаріших є запис "respawn" у / etc / inittab ... якщо ви використовуєте стару систему init SysV. Інший метод - використання демона супервізора з пакету daemontools DJ Bernstein . Інші варіанти - використання функцій Ubuntu upstart ... або systemd або інших.

Але ви можете подивитися на альтернативи init та в коді Python для Pardus: зокрема, мудрівський демон.

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

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


3

Ви також можете використовувати монітор або моніторинг процесів за допомогою ps-watcher

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

Ось приклад для вашого сценарію:

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

Погляньте на приклади monit


1

Вам потрібен керівник, ви можете використовувати супервізора . Це супервізор на основі пітона, тому його легко змінити, якщо вам потрібно.

Контроль здійснюється за допомогою файлів із синтаксисом файлу .ini.


0

Відповідь Тердона не працювала для мене, тому що pgrep -f testing.pyніколи не була "невдалою". Це захопить pid для роботи з cron (через опцію -f). Однак без параметра -f pgrep не знайде testing.py, оскільки не існує жодного процесу, який називається testing.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

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)

0

За відповідь Тердона, pgrep -f testing.pyніколи не повернеться помилковим відповідно до коментарів, наведених тут :

Я думаю, що проблема полягає в тому, що 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.