Python démon et systemd service
J'ai un simple script Python fonctionne comme un démon. Je suis en train de créer systemd script pour pouvoir lancer ce script au démarrage.
Actuel systemd script:
[Unit]
Description=Text
After=syslog.target
[Service]
Type=forking
User=node
Group=node
WorkingDirectory=/home/node/Node/
PIDFile=/var/run/zebra.pid
ExecStart=/home/node/Node/node.py
[Install]
WantedBy=multi-user.target
node.py:
if __name__ == '__main__':
with daemon.DaemonContext():
check = Node()
check.run()
run
contient while True
boucle.
J'essaie d'exécuter ce service avec systemctl start zebra-node.service
. Malheureusement, de services jamais été terminé en indiquant la séquence, je dois appuyer sur Ctrl+C.
Le Script est en cours d'exécution, mais le statut est en cours d'activation et après un moment il changer pour la désactivation.
Maintenant, je suis en utilisant python-démon (mais avant j'ai essayé sans et les symptômes étaient similaires).
Dois-je mettre en œuvre certaines des fonctionnalités supplémentaires à mon script ou est systemd fichier incorrect?
- N'a la réponse à résoudre votre problème? Si pas, essayez de définir daemon_context=True lors de la création de la DaemonContext(). Il peut fonctionner.
- C'est dommage, votre code Python exemple n'est pas complète (il manque l'importation de
daemon
et pas clair, où laNode
vient) alors il n'est pas facile/possible de reproduire votre situation. - Cette indirectement liés à la question, mais peut vous aider: unix.stackexchange.com/a/226853/33386
Vous devez vous connecter pour publier un commentaire.
La raison, il ne complète pas la séquence de démarrage, que pour le Type
forking
votre processus de démarrage est prévu à la fourchette et à la sortie (voir $ man systemd.service de recherche de la fourche).Simplement utiliser uniquement le processus principal, ne pas daemonize
Une option est de faire moins. Avec systemd, il n'est souvent pas nécessaire de créer des démons et vous pouvez exécuter directement le code sans daemonizing.
Cela permet à l'aide de simple Type de service appelé
simple
, de sorte que votre unité fichier devrait ressembler.Noter, que la
-u
en python arborescence n'est pas nécessaire, mais dans le cas où vous afficher quelque chose à l'stdout ou stderr, la-u
permet de s'assurer, il n'y a pas de tampon de sortie en place et de lignes imprimées seront immédiatement attiré par systemd et enregistrés dans le journal. Sans elle, il semblerait, avec un peu de retard.Pour cela que j'ai ajouté dans l'unité fichier les lignes
StandardOutput=syslog
etStandardError=syslog
. Si vous ne vous souciez pas de la sortie imprimée dans votre journal, ne se soucient pas de ces lignes (ils n'ont pas à être présent).systemd
fait daemonization obsolètesAlors que le titre de votre question demande explicitement sur daemonizing, je suppose, le cœur de la question est "comment faire mon service en cours d'exécution" et tandis que à l'aide de processus principal semble beaucoup plus simple (vous n'avez pas de soins sur les démons à tous), il pourrait être considéré comme la réponse à votre question.
Je pense, que beaucoup de gens utilisent daemonizing juste parce que "tout le monde le fait". Avec systemd les raisons pour daemonizing sont souvent obsolètes. Il y a peut être quelques raisons d'utiliser daemonization, mais rares sont les cas maintenant.
EDIT: fixe
python -p
bonpython -u
. grâce kmftzg-p
n'est pas une chose, mais-u
est. Voir docs.python.org/3/using/cmdline.html#cmdoption-uIl est possible de daemonize comme Schnouki et Amit décrire. Mais avec systemd, ce n'est pas nécessaire. Il y a deux plus agréable des façons d'initialiser le démon: socket-l'activation et la notification explicite avec sd_notify().
Prise d'activation fonctionne pour les démons qui veulent écouter sur un port réseau ou d'une socket UNIX ou similaire. Systemd ouvrir le socket, écouter, et ensuite lancer le démon lorsqu'une connexion arrive. C'est la meilleure approche, car elle donne plus de souplesse à l'administrateur. [1] et [2] donne une belle introduction, [3] décrit l'API C, tandis que [4] décrit l'API Python.
[1] http://0pointer.de/blog/projects/socket-activation.html
[2] http://0pointer.de/blog/projects/socket-activation2.html
[3] http://www.freedesktop.org/software/systemd/man/sd_listen_fds.html
[4] http://www.freedesktop.org/software/systemd/python-systemd/daemon.html#systemd.daemon.listen_fds
Notification explicite signifie que le démon ouvre les prises de lui-même et/ou n'importe quel autre initialisation, puis en informe init qu'il est prêt et peut répondre à des demandes. Cela peut être mis en œuvre avec le "fork de protocole", mais en réalité il est plus agréable de simplement envoyer une notification à systemd avec sd_notify().
Wrapper Python est appelé à systemd.le démon.informer et aura une ligne à utiliser [5].
[5] http://www.freedesktop.org/software/systemd/python-systemd/daemon.html#systemd.daemon.notify
Dans ce cas, l'unité fichier auraient Type=informer, et de les appeler
systemd.le démon.notify("PRÊT=1") après qu'il a établi les sockets. Pas de bifurquer ou daemonization est nécessaire.
systemd.daemon
via pip?Vous n'êtes pas créer le fichier PID.
systemd s'attend votre programme pour écrire son PID dans
/var/run/zebra.pid
. Comme vous ne le faites pas, systemd pense probablement que votre programme est un échec, d'où le désactivant.Pour ajouter le fichier PID, installer lockfile et modifiez votre code pour cela:
(Note: certaines récente mise à jour de
lockfile
changé son API et de fait incompatible avec python-démon. Pour le corriger, modifierdaemon/pidlockfile.py
, supprimerLinkFileLock
par les importations, et d'ajouterfrom lockfile.linklockfile import LinkLockFile as LinkFileLock
.)Attention d'une autre chose:
DaemonContext
change le dossier de travail de votre programme de/
, faisant de laWorkingDirectory
de votre service de fichiers inutiles. Si vous voulezDaemonContext
à chdir dans un autre répertoire, utilisezDaemonContext(pidfile=pidfile, working_directory="/path/to/dir")
.DaemonContext
change le répertoire de travail du programme vient d'être résolu mes problèmes daemonzingimport daemon.pidfile
et pasimport daemon.pidlockfile
Aussi, vous aurez très probablement besoin de définir
daemon_context=True
lors de la création de laDaemonContext()
.C'est parce que, si
python-daemon
détecte que si elle est en cours d'exécution en vertu d'un système d'init, il ne veut pas se détacher du processus parent.systemd
s'attend à ce que le démon processus en cours d'exécution avecType=forking
va le faire. Par conséquent, vous avez besoin que, d'autresystemd
vais garder en attente, et enfin tuer le processus.Si vous êtes curieux, dans
python-daemon
s'démon module, vous allez voir ce code:J'espère que cela explique mieux.
Je suis tombé sur cette question lors de la tentative de convertir certains python init.d services à systemd sous CentOS 7. Cela semble fonctionner très bien pour moi, par le fait de placer ce fichier dans
/etc/systemd/system/
:J'ai ensuite laissé tomber mon ancien init.d fichier de service de
/etc/init.d
et a courusudo systemctl daemon-reload
pour recharger systemd.Je voulais que mon service de redémarrage automatique, donc les options de redémarrage. J'ai aussi trouvé à l'aide de
idle
pourType
fait plus de sens quesimple
.Plus de détails sur les options que j'ai utilisé ici.
J'ai également expérimenté avec le maintien de l'ancien service et avoir systemd resart le service, mais j'ai rencontré quelques problèmes.
Les problèmes que j'ai rencontré était que l'init.d service de script a été utilisé à la place du service systemd si les deux ont le même nom. Si vous avez tué l'init.d initié le processus, la systemd script seraient alors prendre le relais. Mais si vous avez exécuté
service <service-name> stop
il renvoie à l'ancien init.d service. J'ai donc trouvé le meilleur moyen était d'abandonner la vieille init.d et le service de commande visé à l'systemd service à la place.Espérons que cette aide!