Jak stworzyć demona w Pythonie?

244

Wyszukiwanie w Google ujawnia fragmenty kodu x2. Pierwszym rezultatem jest przepis na ten kod, który zawiera wiele dokumentacji i wyjaśnień, a także kilka przydatnych dyskusji.

Jednak inny przykładowy kod , choć nie zawiera tak dużej dokumentacji, zawiera przykładowy kod do przekazywania poleceń, takich jak start, stop i restart. Tworzy również plik PID, który może być przydatny do sprawdzania, czy demon już działa itp.

Te przykłady wyjaśniają, jak utworzyć demona. Czy są jakieś dodatkowe rzeczy, które należy wziąć pod uwagę? Czy jedna próbka jest lepsza od drugiej i dlaczego?

davidmytton
źródło
1
Zawsze uważałem, że kod demonizacji nie jest potrzebny. Dlaczego nie pozwolić na to powłoce?
emil.p.stanchev
17
Ponieważ nie robi setid ani setpgrp.
bmargulies 24.03.11
4
Użyj supervisord.org . W ten sposób nie musisz rozwidlać () ani przekierowywać na stdin / stderr. Po prostu napisz normalny program.
guettli

Odpowiedzi:

169

Aktualne rozwiązanie

Referencyjna implementacja PEP 3143 (biblioteka procesów demona standardowego) jest teraz dostępna jako demon python .

Odpowiedź historyczna

Próbka kodu Sandera Marechala jest lepsza od oryginału, który został pierwotnie opublikowany w 2004 roku. Kiedyś napisałem demonizator dla Pyro, ale prawdopodobnie użyłbym kodu Sandera, gdybym musiał to zrobić.

Jeff Bauer
źródło
72
Edycja: Od kiedy pierwotnie opublikowałem tę odpowiedź, referencyjna implementacja PEP 3143 jest już dostępna: pypi.python.org/pypi/python-daemon
Jeff Bauer
@JeffBauer Oryginalny link zmarł, pamiętam, że był przydatny, nie spotkałbyś się z linkiem na żywo?
CrazyCasta
1
@CrazyCasta: Wersja Sandera Marechala jest nadal dostępna na Wayback Machine
Jeff Bauer
1
@JeffBauer: Kod Sandera jest wciąż lepszy niż http://pypi.python.org/pypi/python-daemon. Bardziej wiarygodne. Tylko jeden przykład: spróbuj uruchomić dwa razy tego samego demona z python-daemon: dużym brzydkim błędem. Z kodem Sandera: ładny komunikat „Daemon już działa”.
Basj
2
Ponieważ nadal brakuje dokumentacji modułu „python-demon” (patrz także wiele innych pytań SO) i jest raczej niejasny (jak poprawnie uruchomić / zatrzymać demona z wiersza poleceń za pomocą tego modułu?), Zmodyfikowałem próbkę kodu Sandera Marechala, aby dodać quit()metoda wykonywana przed zatrzymaniem demona. Oto jest.
Basj
163

Jest wiele dziwacznych rzeczy, którymi należy się zająć, kiedy zostajesz dobrze zachowanym procesem demona, :

  • zapobiegaj zrzutom rdzenia (wiele demonów działa jako root, a zrzuty rdzenia mogą zawierać poufne informacje)

  • zachowuj się poprawnie wewnątrz chroot więzieniu

  • ustaw UID, GID, katalog roboczy, umask i inne parametry procesu odpowiednio dla przypadku użycia

  • zrezygnować z podwyższonego suid,sgid przywileje

  • zamknij wszystkie otwarte deskryptory plików, z wykluczeniami zależnymi od przypadku użycia

  • zachowują się poprawnie, jeśli zostały uruchomione w już odłączonym kontekście, takim jak init,inetd itp

  • skonfiguruj procedury obsługi sygnałów dla rozsądnego zachowania demona, ale także z konkretnymi procedurami obsługi określonymi przez przypadek użycia

  • przekierować standardowe strumienie stdin, stdout,stderr ponieważ proces demon nie ma już terminal sterujący

  • obsługiwać plik PID jako blokadę doradczą kooperacji, która sama w sobie jest puszką robaków z wieloma sprzecznymi, ale poprawnymi sposobami zachowania

  • umożliwiają prawidłowe czyszczenie po zakończeniu procesu

  • faktycznie stają się procesem demona, nie prowadząc do zombie

Niektóre z nich są standardowe , jak opisano w literaturze kanonicznej Unixa ( Advanced Programming in the UNIX Environment , autorstwa nieżyjącego W. Richarda Stevensa, Addison-Wesley, 1992). Inne, takie jak przekierowanie strumienia i obsługa plików PID , są typowymi zachowaniami większość użytkowników demonów oczekiwałaby, ale są mniej znormalizowane.

Wszystkie są objęte specyfikacją „Standardowa biblioteka procesów demona” PEP 3143 . Python-demon implementacja referencyjna działa na Python 2.7 lub nowsza oraz Python 3.2 lub nowszy.

duży nos
źródło
26
„Gaol” jest napisane poprawnie, ponieważ tak napisał W. Richard Stevens :-)
bignose
7
Gaol to rzecz angielska . Plakat pochodzi z Australii, więc ma sens.
devin
1
Jakieś plany stworzenia wersji przyjaznej dla py3k?
Tim Tisdall 12.03.13
97

Oto mój podstawowy demon Python „Howdy World”, od którego zaczynam, gdy tworzę nową aplikację demona.

#!/usr/bin/python
import time
from daemon import runner

class App():
    def __init__(self):
        self.stdin_path = '/dev/null'
        self.stdout_path = '/dev/tty'
        self.stderr_path = '/dev/tty'
        self.pidfile_path =  '/tmp/foo.pid'
        self.pidfile_timeout = 5
    def run(self):
        while True:
            print("Howdy!  Gig'em!  Whoop!")
            time.sleep(10)

app = App()
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()

Pamiętaj, że będziesz potrzebować python-daemonbiblioteki. Możesz go zainstalować:

pip install python-daemon

Następnie po prostu zacznij od ./howdy.py starti przestań ./howdy.py stop.

Dustin Kirkland
źródło
5
Ten daemonmoduł, który importujesz, nie jest jeszcze standardową częścią Pythona (jeszcze). Musi być zainstalowany z pip install python-daemonlub równoważny.
Nate,
6
Zainstalowałem demona python zgodnie z opisem, ale kiedy próbuję uruchomić moją aplikację (tak samo jak ostatnie 3 linie), pojawia się komunikat ImportError: nie można zaimportować programu uruchamiającego nazwy
Nostradamnit
Czy możesz sprawdzić, czy jest poprawnie zainstalowany? $ dpkg -L demon python | grep runner /usr/share/pyshared/daemon/runner.py
Dustin Kirkland
4
Ta sugestia wydaje się przestarzała - zresztą we wrześniu 2013 r. Python.org/dev/peps/pep-3143 nie wspomina o „programie uruchamiającym ”, który można zaimportować. To oczywiście wyjaśniałoby obserwację @ Nostradamnit.
offby1
2
Nadal działa to dla mnie dobrze, we wrześniu 2013 r., Na Ubuntu 13.04, z zainstalowanymi standardowymi pakietami Python, python2.7 i python-daemon. Jednak w Python3 widzę błąd: „z programu uruchamiającego importowanie demona ImportError: Brak modułu o nazwie„ demon ”
Dustin Kirkland,
42

Zwróć uwagę na demona python pakiet , który rozwiązuje wiele problemów związanych z demonami po wyjęciu z pudełka.

Oprócz innych funkcji umożliwia (z opisu pakietu Debian):

  • Odłącz proces do własnej grupy procesów.
  • Ustaw środowisko procesu odpowiednie do działania w chroot.
  • Zrezygnuj z uprawnień suid i sgid.
  • Zamknij wszystkie otwarte deskryptory plików.
  • Zmień katalog roboczy, uid, gid i umask.
  • Ustaw odpowiednie procedury obsługi sygnałów.
  • Otwórz nowe deskryptory plików dla stdin, stdout i stderr.
  • Zarządzaj określonym plikiem blokady PID.
  • Zarejestruj funkcje czyszczenia dla przetwarzania przy wyjściu.
Viliam
źródło
35

Alternatywą - stworzyć normalny, nie daemonized programu Pythona następnie zewnętrznie daemonize go za pomocą supervisord . Może to zaoszczędzić wiele problemów i jest przenośne * nix i język.

Chris Johnson
źródło
1
Myślę, że to najlepszy sposób. Zwłaszcza jeśli chcesz uruchomić kilka demonów w jednym systemie operacyjnym. Nie koduj, użyj ponownie.
guettli
Upraszcza wiele problemów. Napisałem prawdziwe demony - nie są łatwe.
Chris Johnson
1
Najlepsza odpowiedź jest ukryta tutaj :)
kawing-chiu
1
To jest złoto. Po spędzeniu wielu godzin na próbie uruchomienia demona python jest to gotowe rozwiązanie, które działa dla mnie. Świetna dokumentacja i przykłady sprawiły, że mój demon uruchomił się w kilka minut.
Nikhil Sahu,
17

Prawdopodobnie nie jest to bezpośrednia odpowiedź na pytanie, ale systemd może służyć do uruchamiania aplikacji jako demona. Oto przykład:

[Unit]
Description=Python daemon
After=syslog.target
After=network.target

[Service]
Type=simple
User=<run as user>
Group=<run as group group>
ExecStart=/usr/bin/python <python script home>/script.py

# Give the script some time to startup
TimeoutSec=300

[Install]
WantedBy=multi-user.target

Wolę tę metodę, ponieważ wiele pracy jest dla Ciebie wykonane, a następnie skrypt demona zachowuje się podobnie jak reszta systemu.

-Lub przez

Luke Dupin
źródło
To jest właściwa i rozsądna droga. 1) systemctl start control.service
Musi
7

YapDi to stosunkowo nowy moduł Pythona, który pojawił się w Hacker News. Wygląda całkiem przydatnie, można go użyć do przekonwertowania skryptu Pythona na tryb demona z poziomu skryptu.

Sergey R.
źródło
6

ponieważ python-demon nie obsługuje jeszcze Pythona 3.x iz tego, co można przeczytać na liście mailingowej, może nigdy nie będzie, napisałem nową implementację PEP 3143: pep3143daemon

pep3143daemon powinien obsługiwać co najmniej Python 2.6, 2.7 i 3.x

Zawiera także klasę PidFile.

Biblioteka zależy tylko od biblioteki standardowej i od modułu sześciu.

Może być używany jako kropla zastępująca demona python.

Oto dokumentacja .

Stephan Schultchen
źródło
6

Ta funkcja przekształci aplikację w demona:

import sys
import os

def daemonize():
    try:
        pid = os.fork()
        if pid > 0:
            # exit first parent
            sys.exit(0)
    except OSError as err:
        sys.stderr.write('_Fork #1 failed: {0}\n'.format(err))
        sys.exit(1)
    # decouple from parent environment
    os.chdir('/')
    os.setsid()
    os.umask(0)
    # do second fork
    try:
        pid = os.fork()
        if pid > 0:
            # exit from second parent
            sys.exit(0)
    except OSError as err:
        sys.stderr.write('_Fork #2 failed: {0}\n'.format(err))
        sys.exit(1)
    # redirect standard file descriptors
    sys.stdout.flush()
    sys.stderr.flush()
    si = open(os.devnull, 'r')
    so = open(os.devnull, 'w')
    se = open(os.devnull, 'w')
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())
Ivan Kolesnikov
źródło
5

Obawiam się, że moduł demona wspomniany przez @Dustin nie działał dla mnie. Zamiast tego zainstalowałem demona python i użyłem następującego kodu:

# filename myDaemon.py
import sys
import daemon
sys.path.append('/home/ubuntu/samplemodule') # till __init__.py
from samplemodule import moduleclass 

with daemon.DaemonContext():
    moduleclass.do_running() # I have do_running() function and whatever I was doing in __main__() in module.py I copied in it.

Bieganie jest łatwe

> python myDaemon.py

dla kompletności tutaj jest zawartość katalogu samplemodule

>ls samplemodule
__init__.py __init__.pyc moduleclass.py

Zawartość pliku moduleclass.py może być

class moduleclass():
    ...

def do_running():
    m = moduleclass()
    # do whatever daemon is required to do.
Somum
źródło
2

Jeszcze jedna rzecz do przemyślenia podczas demonizacji w pythonie:

Jeśli używasz rejestrowania w języku Python i chcesz kontynuować korzystanie z niego po demonizacji, pamiętaj o wywołaniu programów close()obsługi (w szczególności programów do obsługi plików).

Jeśli tego nie zrobisz, program obsługi może nadal myśleć, że ma otwarte pliki, a twoje wiadomości po prostu znikną - innymi słowy upewnij się, że program rejestrujący wie, że jego pliki są zamknięte!

Zakłada się, że kiedy demonizujesz, zamykasz WSZYSTKIE otwarte deskryptory plików bez rozróżnienia - zamiast tego możesz spróbować zamknąć wszystkie pliki oprócz plików dziennika (ale zwykle łatwiej jest zamknąć wszystkie, a następnie ponownie otworzyć te, które chcesz).

Matthew Wilcoxson
źródło
Czy uważasz, że otwarcie nowego modułu rejestrującego jest lepsze niż przekazanie modułu rejestrującego do demona przy użyciu na przykład opcji file_preserve pliku DaemonContext?
HeyWatch,
Zamykasz tylko rejestrator, nie tworzysz nowego (po prostu otworzy go ponownie, gdy będzie to konieczne). Ale chociaż jest to naprawdę łatwe, lepiej użyć DaemonContext, ponieważ prawdopodobnie robi on inne sprytne rzeczy (zakładając, że zachowanie nadal pozwala na właściwą demonizację).
Matthew Wilcoxson
2

Chociaż możesz preferować czyste rozwiązanie Python dostarczane przez moduł python-daemon, istnieje daemon(3)funkcja w libc- przynajmniej na BSD i Linux - która zrobi to dobrze.

Wywołanie go z Pythona jest łatwe:

import ctypes

ctypes.CDLL(None).daemon(0, 0) # Read the man-page for the arguments' meanings

Jedyne, co pozostaje do zrobienia, to utworzenie (i zablokowanie) pliku PID. Ale że sobie poradzisz ...

Michaił T.
źródło
1

Zmodyfikowałem kilka wierszy w przykładzie kodu Sandera Marechala (wspomnianym przez @JeffBauer w zaakceptowanej odpowiedzi ), aby dodaćquit() metodę, która zostanie wykonana przed zatrzymaniem demona. Czasami jest to bardzo przydatne.

Oto jest.

Uwaga: nie używam modułu „python-demon”, ponieważ dokumentacja wciąż brakuje (patrz także wiele innych pytań SO) i jest raczej niejasna (jak poprawnie uruchomić / zatrzymać demona z wiersza poleceń za pomocą tego modułu?)

Basj
źródło
-1

Po kilku latach i wielu próbach (wypróbowałem wszystkie podane tutaj odpowiedzi, ale wszystkie miały drobne wady), teraz zdaję sobie sprawę, że istnieje lepszy sposób niż rozpoczęcie, zatrzymanie, zrestartowanie demona bezpośrednio z Pythona : zamiast tego użyj narzędzi systemu operacyjnego.

Na przykład w przypadku systemu Linux zamiast robić python myapp starti python myapp stoprobię to, aby uruchomić aplikację:

screen -S myapp python myapp.py    
CTRL+A, D to detach

lub screen -dmS myapp python myapp.pydo rozpoczęcia i odłączyć go w jednej komendzie .

Następnie:

screen -r myapp

podłączyć ponownie do tego terminala. W terminalu można użyć CTRL + C, aby go zatrzymać.

Basj
źródło
-2

Najłatwiejszym sposobem utworzenia demona za pomocą Pythona jest użycie frameworku Twisted sterowanego zdarzeniami. Obsługuje wszystkie rzeczy niezbędne do demonizacji. Używa Wzorca Reaktora do obsługi równoczesnych żądań.

Travis B. Hartwell
źródło
5
To zdecydowanie za duży młot do użycia. Większość ludzi chce po prostu uruchomić krótki skrypt w języku Python, który napisali jako demon. python-daemon, jak opisano powyżej, jest poprawną odpowiedzią.
Tom Swirly,
2
Chociaż ta odpowiedź była dość arogancka, była użyteczna.
fiatjaf
-28

W 80% przypadków ludzie mówią „demon”, chcą tylko serwera. Ponieważ pytanie w tej kwestii jest całkowicie niejasne, trudno powiedzieć, jaka może być domena odpowiedzi. Ponieważ serwer jest wystarczający, zacznij od tego. Jeśli rzeczywiście potrzebny jest „demon” (jest to rzadki przypadek), czytaj dalejnohup przypadek jako sposób na demonizację serwera.

Do czasu, gdy rzeczywisty demon jest rzeczywiście wymagany, po prostu napisz prosty serwer.

Zobacz także implementację referencyjną WSGI .

Zobacz także Simple HTTP Server .

„Czy są jakieś dodatkowe rzeczy, które należy wziąć pod uwagę?” Tak. Około miliona rzeczy. Jaki protokół? Ile żądań? Jak długo obsługiwać każde żądanie? Jak często będą przyjeżdżać? Czy zastosujesz dedykowany proces? Wątki Podprocesy? Pisanie demona to duże zadanie.

S.Lott
źródło
12
Żadna z tych bibliotek nie robi nawet jednej fork(), a co dopiero dwóch. Nie mają one nic wspólnego z demonizacją.
Brandon Rhodes
8
W systemach operacyjnych Unix proces „demona” - podobnie jak stewardesy, które Grecy nazywali „demonami” - to proces, który „stoi z boku”. Zamiast bezpośrednio obsługujących pojedynczego użytkownika przez TTY danego użytkownika, demon należący do żadnego TTY, ale może odpowiedzieć na prośby wielu użytkowników w systemie, lub - jak crondlub syslogd- czy usługi porządkowe dla całego systemu. Aby utworzyć proces demona, należy przynajmniej wykonać podwójnie - fork()przy zamkniętych wszystkich deskryptorach plików, aby był odporny na sygnały ze wszystkich kontrolujących terminali, w tym konsoli systemowej. Zobacz odpowiedź bignose.
Brandon Rhodes,
5
@S Lott - „serwer” opisuje, co robi proces (nasłuchuje przychodzących żądań zamiast inicjować własne działania); „Demon” opisuje w jaki sposób proces trwa (bez okna lub terminal sterowania). SimpleHTTPServerjest rzeczywiście serwerem, ale takim, który nie wie natywnie, jak się demonizować (możesz na przykład Ctrl-C). nohupto narzędzie do demonizacji naiwnego procesu - więc twój niepodłączony serwer jest rzeczywiście zarówno demonem, jak i serwerem, dokładnie tak, jak twierdzisz. Pytanie przepełnienia stosu było w istocie pytaniem: „Jak mogę zaimplementować nohupw Pythonie?”
Brandon Rhodes,
5
Tak, ale rozumiem pytanie dotyczące PO: chce przeprowadzić demonizację z poziomu swojego programu python i nie używając niczego innego.
Noufal Ibrahim,
4
@S Lott - Nie musisz być pod wrażeniem! Autor każdej innej odpowiedzi wiedział, co znaczy „demon”, więc moja umiejętność interpretacji tego pytania nie jest niczym wyjątkowym. :) A skąd pomysł, że chcę, aby autor wynalazł koło na nowo? Uważam, że nohupjest to dobre narzędzie i usunę mój głos -1, jeśli po prostu przeniesiesz ten użyteczny pomysł do swojej rzeczywistej odpowiedzi. W rzeczywistości, jeśli wspomnisz supervisordi jak to również uratuje autora przed koniecznością rejestrowania, skryptu start-stop i ponownego uruchomienia ograniczania przepustowości, to nawet dam ci +1. :)
Brandon Rhodes