J'aimerais un démoniseur capable de transformer un script ou une commande arbitraire et générique en démon .
Je voudrais traiter deux cas courants:
J'ai un script qui devrait fonctionner pour toujours. S'il meurt (ou au redémarrage), redémarrez-le. Ne laissez jamais deux copies s'exécuter à la fois (détectez si une copie est déjà en cours d'exécution et ne la lancez pas dans ce cas).
J'ai un script simple ou une commande de ligne de commande que j'aimerais continuer à exécuter à plusieurs reprises pour toujours (avec une courte pause entre les exécutions). Encore une fois, n'autorisez pas l'exécution simultanée de deux copies du script.
Bien sûr, il est trivial d'écrire une boucle «while (true)» autour du script dans le cas 2, puis d'appliquer une solution pour le cas 1, mais une solution plus générale résoudra simplement le cas 2 directement puisque cela s'applique au script dans le cas 1 comme eh bien (vous voudrez peut-être juste une pause plus courte ou pas de pause si le script n'est pas destiné à mourir (bien sûr, si le script ne meurt vraiment jamais, la pause n'a pas vraiment d'importance)).
Notez que la solution ne doit pas impliquer, par exemple, l'ajout de code de verrouillage de fichier ou d'enregistrement PID aux scripts existants.
Plus précisément, j'aimerais un programme "daemonize" que je peux exécuter comme
% daemonize myscript arg1 arg2
ou, par exemple,
% daemonize 'echo `date` >> /tmp/times.txt'
qui garderait une liste croissante de dates ajoutées à times.txt. (Notez que si le (s) argument (s) à démoniser est un script qui s'exécute pour toujours comme dans le cas 1 ci-dessus, alors daemonize fera toujours la bonne chose, en le redémarrant si nécessaire.) Je pourrais alors mettre une commande comme ci-dessus dans mon .login et / ou le cron toutes les heures ou toutes les minutes (en fonction de mon inquiétude à ce qu'il meure de façon inattendue).
NB: Le script daemonize devra se souvenir de la chaîne de commande qu'il démonise pour que si la même chaîne de commande est à nouveau démonisée, il ne lance pas une deuxième copie.
En outre, la solution devrait idéalement fonctionner à la fois sur OS X et Linux, mais les solutions pour l'un ou l'autre sont les bienvenues.
EDIT: C'est bien si vous devez l'invoquer avec sudo daemonize myscript myargs
.
(Si je pense à tout cela mal ou qu'il existe des solutions partielles rapides et sales, j'aimerais aussi l'entendre.)
PS: Au cas où cela serait utile, voici une question similaire spécifique à python.
Et cette réponse à une question similaire a ce qui semble être un idiome utile pour une diabolisation rapide et sale d'un script arbitraire:
Réponses:
Vous pouvez démoniser n'importe quel exécutable sous Unix en utilisant nohup et l'opérateur &:
La commande nohup vous permet de fermer votre session shell sans que cela ne tue votre script, tandis que le & place votre script en arrière-plan afin que vous obteniez une invite du shell pour continuer votre session. Le seul problème mineur avec ceci est la sortie standard et l'erreur standard toutes deux envoyées à ./nohup.out, donc si vous démarrez plusieurs scripts dans ce manoir, leur sortie sera entrelacée. Une meilleure commande serait:
Cela enverra le standard vers le fichier de votre choix et l'erreur standard vers un autre fichier de votre choix. Si vous souhaitez utiliser un seul fichier pour la sortie standard et l'erreur standard, vous pouvez utiliser ceci:
Le 2> & 1 indique au shell de rediriger l'erreur standard (descripteur de fichier 2) vers le même fichier que la sortie standard (descripteur de fichier 1).
Pour exécuter une commande une seule fois et la redémarrer si elle meurt, vous pouvez utiliser ce script:
Le premier argument est le nom du fichier pid à utiliser. Le deuxième argument est la commande. Et tous les autres arguments sont les arguments de la commande.
Si vous nommez ce script restart.sh, voici comment vous l'appelleriez:
la source
trap EXIT
)<
danstest
est une comparaison ASCII et non une comparaison entière. Cela peut toujours fonctionner, mais peut entraîner des bogues.Je m'excuse pour la longue réponse (veuillez voir les commentaires sur la façon dont ma réponse correspond aux spécifications). J'essaie d'être compréhensif pour que vous ayez une longueur d'avance aussi bonne que possible. :-)
Si vous êtes en mesure d'installer des programmes (avec un accès root) et que vous êtes prêt à effectuer un travail ponctuel pour configurer votre script pour l'exécution du démon (c'est-à-dire plus compliqué que de simplement spécifier les arguments de ligne de commande à exécuter sur la ligne de commande, mais ne devant être fait qu'une fois par service), j'ai un moyen plus robuste.
Cela implique l'utilisation de daemontools . Le reste de l'article décrit comment configurer des services à l'aide de daemontools.
La configuration initiale
/service
. Le programme d'installation devrait déjà avoir fait cela, mais il suffit de vérifier, ou si l'installation est manuelle. Si vous n'aimez pas cet emplacement, vous pouvez le changer dans votresvscanboot
script, bien que la plupart des utilisateurs de daemontools soient habitués à l'utiliser/service
et seront confus si vous ne l'utilisez pas.init
(c'est-à-dire qui n'utilise pas/etc/inittab
), vous devrez utiliser le pré-installéinittab
comme base pour organisersvscanboot
l'appel parinit
. Ce n'est pas difficile, mais vous devez savoir comment configurer leinit
que votre système d'exploitation utilise.svscanboot
est un script qui appellesvscan
, qui effectue le travail principal de recherche de services; il est appelé à partir de celui-ciinit
,init
il s'arrangera pour le redémarrer s'il meurt pour une raison quelconque.Configuration par service
/var/lib/svscan
, mais tout nouvel emplacement conviendra.J'utilise généralement un script pour configurer le répertoire de services, pour économiser beaucoup de travail manuel répétitif. par exemple,
où
some-service-name
est le nom que vous souhaitez donner à votre service,user
est l'utilisateur sous lequel exécuter ce service etloguser
est l'utilisateur sous lequel exécuter le journal. (La journalisation est expliquée dans quelques instants.)fghack
, bien que cela vienne à un compromis: vous ne pouvez plus contrôler le programme en utilisantsvc
.run
script pour vous assurer qu'il fait ce que vous voulez. Vous devrez peut-être passer unsleep
appel en haut, si vous prévoyez que votre service se termine fréquemment./service
pointant vers votre répertoire de services. (Ne mettez pas de répertoires de services directement à l'intérieur/service
; cela rend plus difficile la suppression du service desvscan
la montre de.)Enregistrement
mkservice
);svscan
prend en charge l'envoi des messages de journal au service de journalisation.mkservice
crée des fichiers journaux horodatés à rotation automatique dans lelog/main
répertoire. Le fichier journal actuel est appelécurrent
.tai64nlocal
traduira les horodatages dans un format lisible par l'homme. (TAI64N est un horodatage atomique 64 bits avec un nombre de nanosecondes.)Services de contrôle
svstat
pour obtenir le statut d'un service. Notez que le service de journalisation est indépendant et a son propre statut.svc
. Par exemple, pour redémarrer votre service, utilisezsvc -t /service/some-service-name
;-t
signifie «envoyerSIGTERM
».-h
(SIGHUP
),-a
(SIGALRM
),-1
(SIGUSR1
),-2
(SIGUSR2
) et-k
(SIGKILL
).-d
. Vous pouvez également empêcher un service de démarrer automatiquement au démarrage en créant un fichier nommédown
dans le répertoire du service.-u
. Cela n'est pas nécessaire sauf si vous l'avez arrêté précédemment (ou configuré pour ne pas démarrer automatiquement).-x
; généralement utilisé avec-d
pour mettre fin au service. C'est la manière habituelle d'autoriser la suppression d'un service, mais vous devez d'abord dissocier le service/service
, sinon voussvscan
redémarrerez le superviseur. De plus, si vous avez créé votre service avec un service de journalisation (mkservice -l
), n'oubliez pas de quitter également le superviseur de journalisation (par exemplesvc -dx /var/lib/svscan/some-service-name/log
) avant de supprimer le répertoire de services.Résumé
Avantages:
init
fournit.Les inconvénients:
svc
et ne pouvez pas exécuter les scripts d'exécution directement (car ils ne seraient alors pas sous le contrôle du superviseur).supervise
processus dans votre table de processus.)Dans l'ensemble, je pense que daemontools est un excellent système pour vos besoins. Je suis ravi de toute question sur la manière de le configurer et de le maintenir.
la source
supervise
, le superviseur, se charge de redémarrer tout service qui sort. Il attend une seconde entre les restars; si ce n'est pas assez de temps pour vous, mettez en veille en haut du script d'exécution du service.supervise
est lui-même soutenu parsvscan
, donc si un superviseur meurt, il sera redémarré. 2b.svscan
est soutenu parinit
, qui redémarrera automatiquementsvscan
si nécessaire. 2c. Si votreinit
meurt pour une raison quelconque, vous êtes foutu de toute façon. :-Psvstat
etsvc
peuvent utiliser.Je pense que vous voudrez peut-être essayer
start-stop-daemon(8)
. Consultez les scripts dans/etc/init.d
n'importe quelle distribution Linux pour des exemples. Il peut trouver les processus démarrés par ligne de commande invoquée ou par fichier PID, de sorte qu'il correspond à toutes vos exigences, sauf en tant que chien de garde pour votre script. Mais vous pouvez toujours démarrer un autre script de surveillance du démon qui redémarre simplement votre script si nécessaire.la source
start-stop-daemon
là non plus (à partir de 10.9).start-stop-daemon
est toujours en vie sur Linux, cependant; mais après avoir lu réponse stackoverflow.com/a/525406/45375 je réalisais que OSX fait sa propre chose:launchd
.Vous devriez jeter un œil à daemonize . Il permet de détecter une seconde copie (mais il utilise un mécanisme de verrouillage de fichier). Il fonctionne également sur différentes distributions UNIX et Linux.
Si vous avez besoin de démarrer automatiquement votre application en tant que démon, vous devez créer un script d'initialisation approprié.
Vous pouvez utiliser le modèle suivant:
la source
killproc
partie d'arrêt: si vous aviez un processus qui, disons, a été exécutéjava
,killproc
cela entraînera la destruction de tous les autres processus Java.$corelimit >/dev/null 2>&1 ; $*
Donc je doute que ça démonise quoi que ce soit ...Comme alternative au déjà mentionné
daemonize
etdaemontools
, il y a le démon commande du paquet libslack.daemon
est assez configurable et se soucie de toutes les tâches fastidieuses du démon telles que le redémarrage automatique, la journalisation ou la gestion des fichiers pid.la source
Si vous utilisez spécifiquement OS X, je vous suggère de jeter un œil au fonctionnement de launchd. Il vérifiera automatiquement que votre script est en cours d'exécution et le relancera si nécessaire. Il comprend également toutes sortes de fonctionnalités de planification, etc. Il doit satisfaire à la fois les exigences 1 et 2.
Pour vous assurer qu'une seule copie de votre script peut s'exécuter, vous devez utiliser un fichier PID. En général, j'écris un fichier dans /var/run/.pid qui contient un PID de l'instance en cours d'exécution. si le fichier existe lorsque le programme s'exécute, il vérifie si le PID dans le fichier est réellement en cours d'exécution (le programme peut avoir planté ou oublié de supprimer le fichier PID). Si c'est le cas, abandonnez. Sinon, lancez l'exécution et écrasez le fichier PID.
la source
Daemontools ( http://cr.yp.to/daemontools.html ) est un ensemble d'utilitaires assez complexes utilisés pour faire cela, écrits par dj bernstein. J'ai utilisé ceci avec un certain succès. La partie ennuyeuse à ce sujet est qu'aucun des scripts ne renvoie de résultats visibles lorsque vous les exécutez - juste des codes de retour invisibles. Mais une fois qu'il fonctionne, il est à l'épreuve des balles.
la source
Obtenez d'abord
createDaemon()
sur http://code.activestate.com/recipes/278731/Puis le code principal:
la source
Ceci est une version de travail complète avec un exemple que vous pouvez copier dans un répertoire vide et essayer (après avoir installé les dépendances CPAN, qui sont Getopt :: Long , File :: Spec , File :: Pid et IPC :: System: : Simple - tous assez standard et sont fortement recommandés pour tout pirate informatique: vous pouvez tous les installer en même temps avec
cpan <modulename> <modulename> ...
).keepAlive.pl:
example.pl:
Vous pouvez maintenant invoquer l'exemple ci-dessus avec:
./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3
et le fichierpidfile
sera créé et vous verrez la sortie:la source
Vous pouvez également essayer Monit . Monit est un service qui surveille et rend compte des autres services. Bien qu'il soit principalement utilisé pour notifier (par e-mail et sms) les problèmes d'exécution, il peut également faire ce que la plupart des autres suggestions ici recommandent. Il peut (re) démarrer et arrêter automatiquement des programmes, envoyer des e-mails, lancer d'autres scripts et maintenir un journal de sortie que vous pouvez récupérer. De plus, j'ai trouvé qu'il était facile à installer et à maintenir car il existe une documentation solide.
la source
Vous pouvez essayer d' immortaliser. C'est un superviseur multiplateforme * nix (indépendant du système d'exploitation).
Pour un essai rapide sur macOS:
Si vous utilisez FreeBSD depuis les ports ou en utilisant pkg:
Pour Linux en téléchargeant les binaires précompilés ou depuis la source: https://immortal.run/source/
Vous pouvez soit l'utiliser comme ceci:
Ou par un fichier de configuration YAML qui vous donne plus d'options, par exemple:
Si vous souhaitez conserver également la sortie d'erreur standard dans un fichier séparé, vous pouvez utiliser quelque chose comme:
la source
J'ai apporté une série d'améliorations sur l' autre réponse .
sleep
)-h
eval
, vous pouvez donc construire n'importe quelle sorte de script shell sous forme de chaîne à envoyer à ce script en tant que dernier argument (ou arguments de fin) pour qu'il démonise-lt
au lieu de<
Voici le script:
Usage:
Sachez que si vous exécutez ce script à partir de répertoires différents, il peut utiliser différents fichiers pid et ne détecter aucune instance en cours d'exécution existante. Puisqu'il est conçu pour exécuter et redémarrer des commandes éphémères fournies via un argument, il n'y a aucun moyen de savoir si quelque chose a déjà été commencé, car qui doit dire s'il s'agit de la même commande ou non? Pour améliorer cette application de l'exécution d'une seule instance de quelque chose, une solution spécifique à la situation est nécessaire.
De plus, pour qu'il fonctionne comme un démon approprié, vous devez utiliser (au minimum) nohup comme le mentionne l'autre réponse. Je n'ai fait aucun effort pour fournir une résistance aux signaux que le processus peut recevoir.
Un autre point à noter est que tuer ce script (s'il a été appelé à partir d'un autre script qui est tué, ou avec un signal) peut ne pas réussir à tuer l'enfant, surtout si l'enfant est encore un autre script. Je ne sais pas pourquoi, mais cela semble être lié à la façon dont
eval
fonctionne, ce qui est mystérieux pour moi. Il peut donc être prudent de remplacer cette ligne par quelque chose qui n'accepte qu'une seule commande comme dans l'autre réponse.la source