Jak automatycznie zrestartować skrypt Pythona, jeśli zostanie zabity lub umrze


31

Korzystam z mojego skryptu Python w tle na moim komputerze Ubuntu (12.04) w ten sposób -

nohup python testing.py > test.out &

Możliwe, że na pewnym etapie moje powyżej Python scriptmogą umrzeć z jakiegokolwiek powodu.

Więc myślę, że mam coś takiego cron agent skrypt powłoki bash, który może automatycznie zrestartować mój powyższy skrypt Pythona, jeśli zostanie zabity z jakiegokolwiek powodu.

Czy to się da zrobić? Jeśli tak, to jaki jest najlepszy sposób rozwiązania tego rodzaju problemu?

AKTUALIZACJA:

Po utworzeniu takiego testing.confpliku -

chdir /tekooz
exec python testing.py
respawn

Uruchomiłem poniżej polecenia sudo, aby go uruchomić, ale nie widzę, że ten proces działa za pomocą 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

Masz pojęcie, dlaczego px ax nic mi nie pokazuje? Jak mogę sprawdzić, czy mój program działa, czy nie?

To jest mój skrypt Pythona -

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

Odpowiedzi:


24

Na Ubuntu (do 14.04, 16.04 i później użyj systemd) możesz użyć do tego upstart, lepiej niż zadanie cron. Wstawiasz konfigurację /etc/initi upewnij się, że podałeś respawn

Może to być plik minimalny /etc/init/testing.conf(edytuj jako root):

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

I możesz przetestować za pomocą /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)

i zacznij od:

sudo start testing

i obserwuj, co się dzieje (w innym oknie) za pomocą:

tail -f /var/tmp/testing.log

i przestań z:

sudo stop testing

Możesz także dodać, [start on][2]aby polecenie startowało podczas uruchamiania systemu.


Jeśli używasz zadania cron, będziesz chciał albo zaimplementować, albo znaleźć kod do niezawodnej obsługi plików PID. Chcesz, aby twoja usługa / skrypt / demon utworzył plik PID (konwencjonalnie zlokalizowany pod / var / run) i sprawdził kod startowy, czy zawartość pliku jest nieaktualna (pozostawiona przez zabity proces). Ten rodzaj kodu jest zaskakująco trudny do napisania bez wyścigów i narożników. stackoverflow.com/questions/788411/…
Jim Dennis

@Zelda: Dzięki za sugestie. Jestem nowy w świecie Linux / Unix. Jakie zmiany mam wprowadzić w /etc/initpliku? Jeśli możesz podać mi przewodnik krok po kroku, będę mógł się czegoś nauczyć i zrobić właściwą rzecz.
arsenał

@Webby Uczyniłem odpowiedź bardziej kompletną. Jeśli nie chcesz otwierać pliku wyjściowego i przepisywać instrukcji drukowania, możesz zrobić sys.stdout = open(file_name, 'w')na początku coś takiego .
Zelda

Dziękuję Zelda. Doceniam twoją pomoc. Zaktualizowałem pytanie o kilka szczegółów. Próbuję zrobić to w ten sposób, aby sprawdzić, czy mój test.py działa, czy nie. Nie pokazuje mi, czy działa, czy nie. px ax | grep testing.py.. Nic mi nie zwraca? Masz pomysł, dlaczego?
arsenał

Powinieneś umieścić całość w klauzuli try / wyjątkiem i zapisać w pliku dziennika, jaki wyjątek został wygenerowany i czy program się kończy. Być może instrukcja print nie działa, ponieważ nie może pisać na standardowe wyjście.
Zelda

20

Możesz także zastosować podejście bardziej zorientowane na powłokę. Mieć swój cronwygląd skryptu i wznowienia go, jeśli obumrze.

  1. Utwórz nowy plik crontab, uruchamiając crontab -e. Spowoduje to wyświetlenie okna Twojego ulubionego edytora tekstu.

  2. Dodaj ten wiersz do właśnie otwartego pliku

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
  3. Zapisz plik i zamknij edytor.

Właśnie utworzyłeś nowy, crontabktóry będzie uruchamiany co 5 minut i uruchom skrypt, chyba że jest już uruchomiony. Zobacz tutaj, aby uzyskać ładny mały samouczek na temat cron. Oficjalne dokumenty Ubuntu crontutaj .

Rzeczywiste uruchamiane polecenie pgrepwyszukuje w uruchomionych procesach ciąg podany w wierszu polecenia. pgrep foowyszuka program o nazwie fooi zwróci jego identyfikator procesu .pgrep -fsprawia, że ​​przeszukuje cały wiersz poleceń użyty do uruchomienia programu, a nie tylko nazwę programu (przydatne, ponieważ jest to skrypt w języku Python).

Te ||środki symbol „to zrobić, jeśli poprzednie polecenie nie powiodło się”. Tak więc, jeśli skrypt nie działa, pgrepnie powiedzie się, ponieważ nic nie znajdzie, a skrypt zostanie uruchomiony.


Dziękuję .. Ale jestem nowy w Linuksie i Uniksie, więc nie wiem, gdzie jest crontab? Czy to gdzieś plik w mojej maszynie Ubuntu?
arsenał

@Webby zobacz zaktualizowaną odpowiedź.
terdon

Dzięki terdon .. Mogę uruchomić tę komendę crontab -ez katalogu, w którym znajduje się mój skrypt Python ..
arsenał

1
@Webby możesz go uruchomić z dowolnego miejsca. cronjest demonem planowania, to usługa działająca w tle. Jeśli twojego skryptu python nie ma w twoim $PATH(jeśli nie możesz go uruchomić z dowolnego miejsca, ale musisz znajdować się w jego katalogu), użyj pełnej ścieżki do skryptu, jak w mojej zaktualizowanej odpowiedzi.
terdon

Dzięki. Teraz ma to sens .. Właśnie utworzyłem nowy plik crontab i edytowałem plik, dodając tę ​​samą pojedynczą linię, ale przez 1 minutę .. Stworzyłem już skrypt Hello World Python obracający się wokół, a True nazwany jako test.py .. Po zapisaniu plik crontab, powinien automatycznie uruchomić test.py po 1 minucie? A następnie sprawdzaj co minutę, czy skrypt Pythona działa, czy nie? Jeśli tak, po zapisaniu pliku crontab -e zrobiłem ps ax | grep testing.py i nie widzę żadnego procesu?
arsenał

6

Program testowy może przekierować dane wyjściowe za pomocą opcji wiersza polecenia, a następnie użyć prostego skryptu python, aby ponownie uruchomić program na czas nieokreślony:

import subprocess

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

możesz umieścić ten program w tle, a gdy chcesz przestać, po prostu wyciągnij go na pierwszy plan i zabij.


6

Tak naprawdę nie powinieneś tego używać do produkcji, ale możesz:

#!/bin/sh

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

Jeśli z jakiegoś powodu proces Pythona zostanie zamknięty, pętla powłoki będzie kontynuowana i uruchomi ją ponownie, dołączając do .outpliku zgodnie z potrzebami. Prawie brak kosztów ogólnych i zajmuje bardzo mało czasu.


6

Istnieje wiele sposobów monitorowania i odradzania procesów w systemie UNIX / Linux. Jednym z najstarszych jest wpis „respawn” w / etc / inittab ... jeśli używasz starego systemu inicjującego SysV. Inną metodą jest użycie demona nadzorcy z pakietu daemontools DJ Bernsteina . Inne opcje to użycie funkcji w Ubuntu upstart ... lub systemd lub innych.

Ale możesz spojrzeć na alternatywę init i kod Pythona dla Pardus: w szczególności demona mudur .

Jeśli zdecydujesz się na zadanie cron (i obsługę plików PID), rozważ przeczytanie tego PEP 3143 i być może skorzystanie z jego referencyjnej implementacji.

Jak wspomniałem w innych komentarzach, solidna obsługa plików PID jest trudna. Jest podatny na wyścigi i walizki narożne. Staje się trudniejsze, jeśli istnieje szansa, że ​​plik PID znajdzie się w systemie plików NFS lub innym sieciowym systemie plików (pewna atomowość gwarantuje, że otrzymujesz semantykę obsługi plików w odpowiednich lokalnych systemach plików UNIX / Linux w niektórych wersjach i implementacjach NFS, na przykład). Również semantyka wokół blokowania plików w systemie UNIX może być trudna. (Czy blokada flocklub fcntlblokada jest natychmiast zwalniana w docelowym systemie operacyjnym, gdy na przykład proces trzymający ją zostaje zabity przez SIGKILL?).


3

Można również użyć Monit Or proces monitorowania z ps-Watcher

Monit to narzędzie typu open source do zarządzania i monitorowania procesów, programów, plików, katalogów i systemów plików w systemie UNIX. Monit przeprowadza automatyczną konserwację i naprawę oraz może wykonywać znaczące działania przyczynowe w sytuacjach błędów.

Oto przykład twojego scenariusza:

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

Spójrz na przykłady monitorów


1

Potrzebujesz przełożonego, którego możesz użyć przełożonego . Jest to superwizor oparty na pythonie, dlatego w razie potrzeby można go łatwo modyfikować.

Sterowanie odbywa się za pomocą plików o składni pliku .ini.


0

Odpowiedź Terdona nie działała dla mnie, ponieważ pgrep -f testing.pynigdy nie „ zawodziła ”. Pobierałby pid dla zadania cron (z powodu opcji -f). Jednak bez opcji -f pgrep nie znajdzie test.py, ponieważ nie ma procesu o nazwie testing.py.

Moim rozwiązaniem tego było zmienić

pgrep -f testing.py

do

pgrep -f testing.py | pgrep python

oznacza to, że pełna praca crontab to:

*/5 * * * * pgrep -f testing.py | pgrep python || nohup python /home/you/scripts/testing.py > test.out

0

W moim przypadku, jako szybką poprawkę, chciałem, aby mój program działał, gdy zakończył działanie z błędem lub został zabity. Z drugiej strony chciałem zatrzymać wykonywanie, gdy program zakończy się poprawnie (kod powrotu = 0)

Przetestowałem to na Bash. Powinien działać dobrze w każdej innej powłoce

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

Dla odpowiedzi terdona, pgrep -f testing.pynigdy nie zwróci fałszu zgodnie z komentarzami tutaj :

Myślę, że problem polega na tym, że cron spawnuje powłokę, aby uruchomić polecenie, a argumenty tej powłoki są dopasowane przez pgrep, ponieważ używasz -f

Bo odpowiedź Matta pgrep -f testing.pyjest bezużytecznapgrep python pasuje do dowolnego działającego skryptu Python. Więc jeśli dwa cronjob ze skryptem Python, drugi cronjob nigdy się nie uruchomi.

A potem znalazłem rozwiązanie do rozwiązania pgrep -f testing.pyw komentarzu tutaj: https://askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

Mój cron do uruchamiania dwóch skryptów 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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.