Python'da nasıl bir daemon yaratırsınız?


244

Google'da arama yapıldığında x2 kod snippet'leri gösterilir. İlk sonuç, altında bazı yararlı tartışmaların yanı sıra birçok dokümantasyon ve açıklama içeren bu kod tarifidir.

Bununla birlikte, başka bir kod örneği , çok fazla dokümantasyon içermemesine rağmen, start, stop ve restart gibi komutları iletmek için örnek kod içerir. Ayrıca, arka plan programının zaten çalışıp çalışmadığını kontrol etmek için kullanışlı bir PID dosyası oluşturur.

Bu örneklerin her ikisi de arka plan programının nasıl oluşturulacağını açıklar. Dikkate alınması gereken başka şeyler var mı? Bir örnek diğerinden daha iyi mi, neden?


1
Daemonization kodunu her zaman gereksiz buldum. Neden sadece kabuğun yapmasına izin vermiyorsun?
emil.p.stanchev

17
Çünkü setid veya setpgrp yapmaz.
Mart'ta

4
Supervisord.org'u kullanın . Bu şekilde stdin / stderr'yi çatallamanıza () veya yönlendirmenize gerek yoktur. Sadece normal bir program yazın.
guettli

Yanıtlar:


169

Mevcut çözüm

PEP 3143'ün (Standart daemon süreç kütüphanesi) referans uygulaması artık python-daemon olarak kullanılabilir .

Tarihsel cevap

Sander Marechal'ın kod örneği orijinal olarak 2004'te yayınlanan orijinalinden daha üstündür. Bir keresinde Pyro için bir cini oluşturdum, ancak bunu yapmak zorunda kalsam muhtemelen Sander'in kodunu kullanırdım.


72
Düzenleme: Aslında bu yanıtı gönderdi beri, şimdi kullanılabilir PEP 3143 bir referans uygulaması: pypi.python.org/pypi/python-daemon
Jeff Bauer

@JeffBauer Orijinal bağlantı öldü, yararlı olduğunu hatırlıyorum, bunun için canlı bir bağlantı bilmezdiniz?
CrazyCasta

1
@CrazyCasta: Sander Marechal'ın versiyonu hala Wayback Machine'de
Jeff Bauer

1
@JeffBauer: Sander'in kodu hala daha iyi http://pypi.python.org/pypi/python-daemon. Daha güvenilir. Sadece bir örnek: aynı cini iki kere başlatmayı deneyin python-daemon: büyük çirkin hata Sander'in koduyla: güzel bir uyarı "Daemon zaten çalışıyor."
Ocak'ta Basj

2
"Python-daemon" modülü belgeleri hala eksik olduğundan (diğer birçok SO sorusuna da bakınız) ve oldukça belirsiz olduğundan (bu modülle komut satırından bir daemon nasıl düzgün bir şekilde başlatılır / durdurulur?), Eklemek için Sander Marechal'ın kod örneğini değiştirdim quit()arka plan programı durdurulmadan önce çalıştırılan yöntem. İşte burada.
16'da Basj

163

Orada birçok keman şey bir hale yaparken bakmak uslu ve arka planda çalışan :

  • çekirdek dökümlerini önleme (birçok cin, kök olarak çalışır ve çekirdek dökümleri hassas bilgiler içerebilir)

  • bir chrootgaol içinde doğru davranmak

  • UID, GID, çalışma dizini, umask ve diğer işlem parametrelerini kullanım durumu için uygun şekilde ayarlama

  • yükseltilmiş suid, sgidayrıcalıklardan vazgeç

  • Kullanım durumuna bağlı olarak hariç tutulan tüm açık dosya tanımlayıcılarını kapatın

  • Zaten müstakil bağlamda iç başladıysanız, doğru davranmak gibi init, inetdvb

  • mantıklı daemon davranışı için sinyal işleyicileri oluşturmanın yanı sıra kullanım durumu tarafından belirlenen özel işleyicileri de ayarlama

  • standart akışları yönlendirme stdin, stdout, stderrbir arka planda çalışan artık bir kontrol terminali beri

  • Bir PID dosyasını , kendi içinde birçok çelişkili ama geçerli davranış biçimiyle solucan kutularından oluşan bir kooperatif danışma kilidi olarak ele alın

  • işlem sonlandırıldığında düzgün temizlemeye izin ver

  • aslında zombilere yol açmadan bir daemon süreci haline gelir

Bunlardan bazıları standarttır , kanonik Unix literatüründe açıklandığı gibi ( UNIX Ortamında İleri Programlama , merhum W. Richard Stevens, Addison-Wesley, 1992). Böyle akışı yönlendirme ve Diğerleri, PID dosya işleme vardır geleneksel davranış çoğu cin kullanıcıları beklenir ama bu daha az standardize edilmiştir.

Bunların tümü PEP 3143 “Standart arka plan süreci kitaplığı” belirtimi kapsamındadır . Piton-cin referans uygulama ya da geç Python 2.7 üzerinde çalışır ve daha sonra Python 3.2 veya.


26
“Gaol” doğru yazılmış, çünkü W. Richard Stevens bu şekilde heceledi :-)
bignose

7
Gaol İngilizce bir şeydir . Poster Avustralya'dan geliyor, bu yüzden mantıklı.
devin

1
Py3k dostu bir sürüm yapmayı planlıyor musunuz?
Tim Tisdall

97

İşte yeni bir daemon uygulaması geliştirirken başladığım temel 'Howdy World' Python arka plan programım.

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

python-daemonKütüphaneye ihtiyacınız olacağını unutmayın . Yükleyebilirsiniz:

pip install python-daemon

Sonra sadece ile başlayın ./howdy.py startve ile durdurun ./howdy.py stop.


5
daemonİçe aktardığınız modül Python'un (henüz) standart bir parçası değil. pip install python-daemonVeya eşdeğeri ile kurulması gerekir .
Nate

6
Açıkladığınız gibi python-daemon yükledim, ancak uygulamamı çalıştırmaya çalıştığımda (son 3 satırınızla aynı), ImportError'u alıyorum: name runner'ı içe aktaramıyorum
Nostradamnit

Düzgün kurulup kurulmadığını kontrol edebilir misiniz? $ dpkg -L python-daemon | grep runner /usr/share/pyshared/daemon/runner.py
Dustin Kirkland

4
Bu öneri eski gibi görünüyor - Eylül 2013 itibariyle, python.org/dev/peps/pep-3143 ithal edilebilecek bir "koşucu" dan bahsetmiyor. Bu elbette @ Nostradamnit'in gözlemini açıklayacaktır.
offby1

2
Bu, Eylül 2013'te Ubuntu 13.04'te stok Python paketleri, python2.7 ve python-daemon yüklü olarak benim için hala iyi çalışıyor. Python3 ile, ancak, ben "cin ithalat koşucu ImportError gelen: 'cin' adlı Hiçbir modülü", hataları görmek
Dustin Kirkland

42

Not piton-cin kutunun dışında cinleri arkasında pek çok soruna çözer paketi.

Diğer özellikleri arasında (Debian paket tanımından):

  • Süreci kendi süreç grubuna ayırın.
  • Proses ortamını bir chroot içinde çalışmaya uygun şekilde ayarlayın.
  • Suid ve sgid ayrıcalıklarından vazgeç.
  • Tüm açık dosya tanımlayıcılarını kapatın.
  • Çalışma dizinini, uid, gid ve umask'i değiştirin.
  • Uygun sinyal işleyicileri ayarlayın.
  • Stdin, stdout ve stderr için yeni dosya tanımlayıcıları açın.
  • Belirtilen bir PID kilit dosyasını yönetin.
  • Çıkışta işleme için temizleme işlevlerini kaydedin.

35

Bir alternatif - normal, daemonize edilmemiş bir Python programı oluşturun ve ardından süpervizör kullanarak harici olarak daemonize edin . Bu çok fazla baş ağrısından kurtulabilir ve * nix- ve dil-taşınabilir.


1
Bence bu en iyi yol. Özellikle bir işletim sisteminde birkaç artalan çalıştırmak istiyorsanız. Kodlama, yeniden kullanma.
guettli

Birçok sorunu basitleştirir. Gerçek cinler yazdım - kolay değiller.
Chris Johnson

1
En iyi cevap burada gizli :)
kawing-chiu

1
Bu altın. Python-daemon'dan geçmeye çalışarak saatler geçirdikten sonra, bu benim için çalışan kutunun dışında bir çözüm. Harika belgeler ve örnekler benim daemon birkaç dakika içinde çalışır hale getirdi.
Nikhil Sahu

17

Muhtemelen soruya doğrudan bir cevap değildir, ancak systemd uygulamanızı bir daemon olarak çalıştırmak için kullanılabilir. İşte bir örnek:

[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

Bu yöntemi tercih ediyorum çünkü birçok iş sizin için yapılıyor ve sonra daemon betiğiniz sisteminizin geri kalanına benzer şekilde davranıyor.

-Veya tarafından


Bu uygun ve aklı başında bir yoldur. 1) /etc/systemd/system/control.service systemctl start control.service
sitesine

7

YapDi , Hacker News'da ortaya çıkan nispeten yeni bir python modülüdür. Oldukça kullanışlı görünüyor, bir python betiğini betiğin içinden daemon moduna dönüştürmek için kullanılabilir.


6

python-daemon henüz python 3.x'i desteklemediğinden ve posta listesinden ne okunabileceğinden, asla olmayacak, PEP 3143'ün yeni bir uygulamasını yazdım: pep3143daemon

pep3143daemon en az python 2.6, 2.7 ve 3.x'i desteklemelidir

Ayrıca bir PidFile sınıfı içerir.

Kütüphane sadece standart kütüphaneye ve altı modüle bağlıdır.

Python-daemon'un yerine bir damla olarak kullanılabilir.

İşte belgeler .


6

Bu işlev bir uygulamayı bir arka plan programına dönüştürür:

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())

5

Korkarım @Dustin'in bahsettiği arka plan modülü benim için çalışmadı. Bunun yerine python-daemon'u kurdum ve aşağıdaki kodu kullandım:

# 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.

Koşmak kolaydır

> python myDaemon.py

tam olarak burada örnek dizin içeriği örnekleme

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

Moduleclass.py içeriği

class moduleclass():
    ...

def do_running():
    m = moduleclass()
    # do whatever daemon is required to do.

2

Python'da arka plan oluştururken düşünülmesi gereken bir şey daha var:

Python günlüğü kullanıyorsanız ve arka plan oluşturduktan sonra kullanmaya devam etmek istiyorsanız close(), işleyicileri (özellikle dosya işleyicileri) çağırdığınızdan emin olun .

Bunu yapmazsanız, işleyici hala dosyalarının açık olduğunu düşünebilir ve mesajlarınız kaybolacaktır - başka bir deyişle, kaydedicinin dosyalarının kapalı olduğunu bildiğinden emin olun!

Bu, TÜM açık dosya tanımlayıcılarını ayrım gözetmeden TÜMÜ'nü kapattığınızı varsaydığınızda - bunun yerine günlük dosyaları dışında tümünü kapatmayı deneyebilirsiniz (ancak genellikle hepsini kapatmak ve sonra istediğinizi yeniden açmak daha kolaydır).


Yeni bir günlük tutucuyu açmak, örneğin DaemonContext'in files_preserve seçeneğini kullanarak günlük tutucuyu arka plan programına aktarmaktan daha mı iyi?
HeyWatchThis

Yalnızca kaydediciyi kapatıyorsunuz, yeni bir tane oluşturmuyorsunuz (gerektiğinde yeniden açılacaktır). Ancak bunu yapmak gerçekten kolay olsa da, DaemonContext'i muhtemelen başka akıllı şeyler yaptığı için kullanmak daha iyi olabilir (korumanın hala düzgün bir daemonizasyona izin verdiği varsayılarak).
Matthew Wilcoxson

2

Python-daemon modülü tarafından sağlanan saf Python çözümünü tercih etmenize rağmen, en azından BSD ve Linux'ta doğru olanı yapacak bir daemon(3)fonksiyon var .libc

Python'dan aramak kolaydır:

import ctypes

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

Geriye kalan tek şey PID dosyasının oluşturulması (ve kilitlenmesi). Ama kendinizi idare edebileceğiniz ...


1

Sander Marechal'ın kod örneğinde ( kabul edilen cevapta @JeffBauer tarafından bahsedilir) birkaç satır değiştirdim ve quit()bu daemon durmadan önce çalıştırılan bir yöntem eklemek için . Bu bazen çok faydalıdır.

İşte burada.

Not: "Python-daemon" modülünü kullanmıyorum çünkü belgeler hala eksik (diğer birçok SO sorusuna da bakınız) ve oldukça belirsiz (bu modül ile komut satırından düzgün bir şekilde nasıl bir daemon başlatılır / durdurulur?)


-1

Birkaç yıl ve birçok denemeden sonra (burada verilen tüm cevapları denedim, ancak hepsinin sonunda küçük dezavantajları vardı), şimdi doğrudan bir Python'dan bir daemon başlatmak, durdurmak ve yeniden başlatmak istemekten daha iyi bir yol olduğunu anlıyorum. : bunun yerine işletim sistemi araçlarını kullanın.

Örneğin, Linux için yerine yapmanın python myapp startve python myapp stopben Uygulamayı başlatmak için şunu yapın:

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

ya screen -dmS myapp python myapp.pyhiç başlayacak ve tek komutla bunu ayırmak .

Sonra:

screen -r myapp

tekrar bu terminale takın. Terminalde bir kez, durdurmak için CTRL + C kullanmak mümkündür.


-2

Python ile arka plan programı oluşturmanın en kolay yolu Twisted olay odaklı çerçeveyi kullanmaktır. Sizin için arka plan programı için gerekli olan her şeyi işler. Eşzamanlı istekleri işlemek için Reaktör Kalıbı'nı kullanır .


5
Kullanmak için çok büyük bir çekiç. Çoğu insan sadece bir daemon olarak yazdıkları kısa bir Python betiği çalıştırmak ister. python-daemon, yukarıda açıklandığı gibi, doğru cevaptır.
Tom Swirly

2
Bu cevap oldukça kibirli olmasına rağmen faydalıydı.
fiatjaf

-28

Zamanın% 80'i, insanlar "daemon" dediğinde, sadece bir sunucu istiyorlar. Soru bu noktada tamamen belirsiz olduğundan, olası cevap alanlarının ne olabileceğini söylemek zor. Bir sunucu yeterli olduğundan, buradan başlayın. Gerçek bir "arka plan programı" gerçekten gerekliyse (bu nadirdir), nohupbir sunucuyu arka plan programı olarak okumaya devam edin .

Gerçek bir daemon olarak gerekli olana kadar, basit bir sunucu yazmanız yeterlidir.

Ayrıca WSGI başvuru uygulamasına bakın.

Ayrıca Basit HTTP Sunucusuna da bakın .

"Dikkate alınması gereken başka şeyler var mı?" Evet. Yaklaşık bir milyon şey. Ne protokolü? Kaç istek? Her talebe ne kadar süre hizmet verilir? Ne sıklıkta gelecekler? Özel bir süreç kullanacak mısınız? İş Parçacığı? Subprocesses? Bir daemon yazmak büyük bir iştir.


12
Bu kütüphanelerin hiçbiri, fork()iki tane bile , tek bir tane bile yapmıyor . Onların daemonizasyon ile ilgisi yoktur.
Brandon Rhodes

8
Unix işletim sistemlerinde, Yunanlıların “cinler” olarak adlandırdığı hava görevlileri gibi bir “daemon” süreci “yanda duran” bir süreçtir. Bu kullanıcının TTY'si aracılığıyla doğrudan tek bir kullanıcıya hizmet etmek yerine, bir arka plan programı TTY'ye ait değildir, ancak sistemdeki birçok kullanıcının isteklerine cevap verebilir crondveya syslogdtüm sistem için temizlik hizmetlerini beğenebilir veya beğenebilir . Bir arka plan programı oluşturmak için, en azından bir çift - fork()tüm dosya tanımlayıcıları kapalı olarak gerçekleştirilmelidir, böylece sistem konsolu da dahil olmak üzere tüm kontrol terminallerinden gelen sinyallere karşı bağışıklık kazanır. Bakınız bignose cevabı.
Brandon Rhodes

5
@S Lott - “Bir sunucu” Bir süreç açıklar yapar (yerine kendi eylemlerini başlatılması gelen istekler için dinler); “Arka plan programı” bir işlemin nasıl çalıştığını açıklar (pencere veya kontrol terminali olmadan). SimpleHTTPServeraslında bir sunucudur, ancak yerel olarak kendini nasıl daemonize edeceğini bilmeyen bir sunucudur (örneğin Ctrl-C'yi kullanabilirsiniz). nohupsenin nohupped sunucu gerçekten de bu yüzden - Bir naif süreci Artalanda için bir araçtır hem bir cin ve sen iddia tam olarak bir sunucu. Bu Yığın Taşması sorusu aslında şu soruyu soruyordu: “ nohupPython'da nasıl uygulayabilirim ?”
Brandon Rhodes

5
Evet öyle ama OPs sorusunu benim anlayışım, ponton programından ve başka bir şey kullanmadan daemonizasyonu yapmak istemesidir.
Noufal Ibrahim

4
@S Lott - Etkilenmenize gerek yok! Diğer her cevabın yazarı “daemon” un ne anlama geldiğini biliyordu, bu yüzden bu soruyu yorumlama yeteneğim pek benzersiz değil. :) Ve yazarın tekerleği yeniden icat etmesini istediğim fikrini nereden buldun? Bence nohupiyi bir araçtır ve eğer bu yararlı fikri gerçek cevabınıza taşırsanız -1 oyumu kaldıracağım. Aslında, supervisordyazarın günlüğe kaydetmeyi, bir start-stop komut dosyasını ve azaltmayı yeniden başlatmayı da nasıl kurtaracağından bahsederseniz , o zaman sizi + 1'leyeceğim. :)
Brandon Rhodes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.