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 cronsą tutaj .

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.