Recherche sur Google révèle des extraits de code x2. Le premier résultat est cette recette de code qui a beaucoup de documentation et d’explications, ainsi que des discussions utiles en dessous.
Cependant, n autre exemple de code , bien que ne contenant pas tant de documentation, inclut un exemple de code permettant de passer des commandes telles que démarrer, arrêter et redémarrer. Il crée également un fichier PID qui peut être utile pour vérifier si le démon est déjà en cours d'exécution, etc.
Ces exemples expliquent comment créer le démon. Y a-t-il d'autres éléments à prendre en compte? Un échantillon est-il meilleur que l'autre et pourquoi?
Solution actuelle
Une implémentation de référence de PEP 3143 (bibliothèque de processus de démon standard)] est maintenant disponible sous la forme python-daemon .
Réponse historique
Le exemple de code de Sander Marechal est supérieur à l'original, qui avait été posté en 2004. J'ai déjà contribué à un démoniseur pour Pyro, mais j'utiliserais probablement le code de Sander si je devais le refaire.
Il y a beaucoup de choses délicates à prendre en charge pour devenir un processus démon bien comporté :
empêcher les vidages de base (de nombreux démons sont exécutés en tant que root et les vidages de base peuvent contenir des informations sensibles)
se comporter correctement à l'intérieur d'une prison chroot
définir l'UID, le GID, le répertoire de travail, l'umask et d'autres paramètres de processus de manière appropriée pour le cas d'utilisation
abandonne les privilèges suid
, sgid
élevés
ferme tous les descripteurs de fichiers ouverts, avec des exclusions selon le cas d'utilisation
se comporte correctement s'il est démarré dans un contexte déjà détaché, tel que init
, inetd
, etc.
configurer des gestionnaires de signaux pour le comportement sensible des démons, mais aussi avec des gestionnaires spécifiques déterminés par le cas d'utilisation
redirige les flux standard stdin
, stdout
, stderr
car un processus démon n'a plus de terminal de contrôle
gérer un fichier PID comme un verrou consultatif coopératif, qui est un ne boîte de Pandore en soi avec de nombreuses façons contradictoires mais valables de se comporter
permettre un nettoyage correct lorsque le processus est terminé
devenir réellement un processus de démon sans conduire à zombies
Certains d'entre eux sont standard , comme décrit dans la littérature canonique Unix ( Programmation avancée dans l'environnement UNIX , par le regretté W. Richard Stevens, Addison-Wesley, 1992). D'autres, telles que la redirection de flux et traitement du fichier PID , ont un comportement classique auquel s'attendent la plupart des utilisateurs de démons, mais qui sont moins normalisées.
Tous ces éléments sont couverts par la spécification PEP 314 "Bibliothèque de processus standard démon" . L'implémentation de référence python-daemon fonctionne sur Python 2.7 ou version ultérieure, et sur Python 3.2 ou version ultérieure.
Voici le démon de base 'Howdy World' Python de base par lequel je commence lorsque je développe une nouvelle application démon.
#!/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()
Notez que vous aurez besoin de la bibliothèque python-daemon
. Vous pouvez l'installer par:
pip install python-daemon
Ensuite, lancez-le simplement avec ./howdy.py start
et arrêtez-le avec ./howdy.py stop
.
Notez le paquet python-daemon qui résout beaucoup de problèmes derrière les démons.
Parmi d'autres fonctionnalités, il permet (à partir de la description du paquet Debian):
Une alternative - créer un programme Python normal et non démonisé, puis le démoniser en externe à l'aide de supervisord . Cela peut économiser beaucoup de maux de tête et est * portable-nix et langue.
Probablement pas une réponse directe à la question, mais systemd peut être utilisé pour exécuter votre application en tant que démon. Voici un exemple:
[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
Je préfère cette méthode car beaucoup de travail est fait pour vous et votre script démon se comporte de la même manière que le reste de votre système.
-Orby
YapDi est un module relativement nouveau python qui est apparu dans Hacker News. A l'air très utile, peut être utilisé pour convertir un script python en mode démon à partir de l'intérieur du script.
comme python-daemon n’a pas encore supporté python 3.x, et à partir de ce qui peut être lu sur la liste de diffusion, il est possible que cela ne se produise jamais, j’ai écrit une nouvelle implémentation de PEP 3143: pep3143daemon
pep3143daemon devrait supporter au moins python 2.6, 2.7 et 3.x
Il contient également une classe PidFile.
La bibliothèque ne dépend que de la bibliothèque standard et du module six.
Il peut être utilisé en remplacement immédiat de python-daemon.
Voici le documentation .
Cette fonction transformera une application en démon:
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())
J'ai bien peur que le module démon mentionné par @Dustin ne fonctionne pas pour moi. Au lieu de cela, j'ai installé python-daemon et utilisé le code suivant:
# 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.
Courir, c'est facile
> python myDaemon.py
juste pour compléter, voici le contenu du répertoire samplemodule
>ls samplemodule
__init__.py __init__.pyc moduleclass.py
Le contenu de moduleclass.py peut être
class moduleclass():
...
def do_running():
m = moduleclass()
# do whatever daemon is required to do.
Une dernière chose à laquelle penser lors de la démonisation en python:
Si vous utilisez python journalisation et que vous souhaitez continuer à l'utiliser après la démonisation, veillez à appeler close()
sur les gestionnaires (en particulier les gestionnaires de fichiers).
Si vous ne le faites pas, le gestionnaire peut toujours penser qu'il a des fichiers ouverts et vos messages disparaîtront tout simplement. En d'autres termes, assurez-vous que l'enregistreur sait que ses fichiers sont fermés!
Cela suppose que lorsque vous démonisez, vous fermez TOUS les descripteurs de fichiers ouverts sans distinction - vous pouvez essayer de fermer tous les fichiers sauf les fichiers journaux (mais il est généralement plus simple de tout fermer puis de rouvrir ceux que vous voulez).
J'ai modifié quelques lignes dans l'exemple de code de Sander Marechal (mentionné par @JeffBauer dans la réponse acceptée ) pour ajouter une méthode quit()
à exécuter préalablement à l'arrêt du démon. C'est parfois très utile.
Note: Je n'utilise pas le module "python-daemon" car la documentation est toujours manquante (voir aussi beaucoup d'autres questions SO) et est assez obscur (comment démarrer/arrêter correctement un démon en ligne de commande avec ce module?)