Ich hätte gerne einen Daemonizer, der aus einem beliebigen, generischen Skript oder Befehl einen Daemon machen kann .
Es gibt zwei häufige Fälle, mit denen ich mich befassen möchte:
Ich habe ein Skript, das für immer laufen sollte. Wenn es jemals stirbt (oder beim Neustart), starten Sie es neu. Lassen Sie niemals zu, dass zwei Kopien gleichzeitig ausgeführt werden (erkennen Sie, ob eine Kopie bereits ausgeführt wird, und starten Sie sie in diesem Fall nicht).
Ich habe ein einfaches Skript oder einen Befehlszeilenbefehl, den ich für immer wiederholt ausführen möchte (mit einer kurzen Pause zwischen den Läufen). Lassen Sie auch hier nicht zu, dass zwei Kopien des Skripts gleichzeitig ausgeführt werden.
Natürlich ist es trivial, in Fall 2 eine "while (true)" - Schleife um das Skript zu schreiben und dann eine Lösung für Fall 1 anzuwenden, aber eine allgemeinere Lösung löst Fall 2 direkt, da dies für das Skript in Fall 1 als gilt gut (Sie möchten vielleicht nur eine kürzere oder keine Pause, wenn das Skript nicht jemals sterben soll (natürlich, wenn das Skript es wirklich tut) die Pause keine Rolle, nie stirbt).
Beachten Sie, dass die Lösung beispielsweise nicht das Hinzufügen von Dateisperrcode oder PID-Aufzeichnung zu den vorhandenen Skripten umfassen sollte.
Insbesondere möchte ich ein Programm "daemonize", das ich gerne ausführen kann
% daemonize myscript arg1 arg2
oder zum Beispiel
% daemonize 'echo `date` >> /tmp/times.txt'
Dadurch würde eine wachsende Liste von Daten an times.txt angehängt. (Beachten Sie, dass wenn das zu dämonisierende Argument ein Skript ist, das für immer wie in Fall 1 oben ausgeführt wird, Daemonize immer noch das Richtige tut und es bei Bedarf neu startet.) Ich könnte dann einen Befehl wie oben in mein .login einfügen und / oder cron es stündlich oder minutiös (je nachdem, wie besorgt ich war, dass es unerwartet sterben würde).
NB: Das Daemonize-Skript muss sich die Befehlszeichenfolge merken, die es dämonisiert, damit beim erneuten Dämonisieren derselben Befehlszeichenfolge keine zweite Kopie gestartet wird.
Außerdem sollte die Lösung idealerweise sowohl unter OS X als auch unter Linux funktionieren, aber Lösungen für das eine oder andere sind willkommen.
EDIT: Es ist in Ordnung, wenn Sie es mit aufrufen müssen sudo daemonize myscript myargs
.
(Wenn ich daran denke, dass alles falsch ist oder es schnelle und schmutzige Teillösungen gibt, würde ich das auch gerne hören.)
PS: Falls es nützlich ist, hier ist eine ähnliche Frage speziell für Python.
Und diese Antwort auf eine ähnliche Frage scheint eine nützliche Redewendung für eine schnelle und schmutzige Dämonisierung eines beliebigen Skripts zu sein:
Antworten:
Sie können jede ausführbare Datei in Unix mit nohup und dem Operator & dämonisieren:
Mit dem Befehl nohup können Sie Ihre Shell-Sitzung beenden, ohne dass Ihr Skript beendet wird, während & Ihr Skript in den Hintergrund stellt, sodass Sie eine Shell-Eingabeaufforderung erhalten, um Ihre Sitzung fortzusetzen. Das einzige kleinere Problem dabei ist, dass Standardausgang und Standardfehler an ./nohup.out gesendet werden. Wenn Sie also mehrere Skripte in diesem Manor starten, wird deren Ausgabe miteinander verflochten. Ein besserer Befehl wäre:
Dadurch wird Standard an die Datei Ihrer Wahl und Standardfehler an eine andere Datei Ihrer Wahl gesendet. Wenn Sie nur eine Datei für Standardausgang und Standardfehler verwenden möchten, können Sie uns Folgendes tun:
2> & 1 weist die Shell an, den Standardfehler (Dateideskriptor 2) in dieselbe Datei wie den Standardausgang (Dateideskriptor 1) umzuleiten.
Um einen Befehl nur einmal auszuführen und neu zu starten, wenn er stirbt, können Sie dieses Skript verwenden:
Das erste Argument ist der Name der zu verwendenden PID-Datei. Das zweite Argument ist der Befehl. Alle anderen Argumente sind die Argumente des Befehls.
Wenn Sie dieses Skript restart.sh nennen, würden Sie es so nennen:
quelle
trap EXIT
)<
intest
ein ASCII-Vergleich und kein ganzzahliger Vergleich ist. Es kann immer noch funktionieren, kann aber zu Fehlern führen.Ich entschuldige mich für die lange Antwort (siehe Kommentare darüber, wie meine Antwort der Spezifikation entspricht). Ich versuche, umfassend zu sein, damit Sie so gut wie möglich sind. :-)
Wenn Sie in der Lage sind, Programme zu installieren (über Root-Zugriff zu verfügen) und bereit sind, einmalige Schritte zu unternehmen, um Ihr Skript für die Daemon-Ausführung einzurichten (dh mehr als nur die Befehlszeilenargumente anzugeben, die in der Befehlszeile ausgeführt werden sollen, Aber ich muss nur einmal pro Service arbeiten. Ich habe einen Weg, der robuster ist.
Es beinhaltet die Verwendung von Daemontools . Der Rest des Beitrags beschreibt, wie Sie Dienste mit Daemontools einrichten.
Ersteinrichtung
/service
. Das Installationsprogramm sollte dies bereits getan haben, aber nur überprüfen oder manuell installieren. Wenn Sie diesen Speicherort nicht mögen, können Sie ihn in Ihremsvscanboot
Skript ändern , obwohl die meisten Daemontools-Benutzer daran gewöhnt sind/service
und verwirrt werden, wenn Sie ihn nicht verwenden.init
(dh nicht verwendet/etc/inittab
), müssen Sie die vorinstallierteinittab
als Basis für die Anordnung verwendensvscanboot
, von der aufgerufen werden sollinit
. Es ist nicht schwer, aber Sie müssen wissen, wie Sie das konfigurieren, dasinit
Ihr Betriebssystem verwendet.svscanboot
ist ein Skript, das aufruftsvscan
und die Hauptarbeit bei der Suche nach Diensten erledigt. Es wird von aufgerufeninit
,init
um einen Neustart zu veranlassen, wenn es aus irgendeinem Grund stirbt.Service-Setup
/var/lib/svscan
, aber jeder neue Ort wird in Ordnung sein.Normalerweise verwende ich ein Skript , um das Dienstverzeichnis einzurichten und viel manuelle Wiederholungsarbeit zu sparen. z.B,
Wo
some-service-name
ist der Name, den Sie Ihrem Dienst geben möchten,user
ist der Benutzer, unter dem dieser Dienst ausgeführt wird, undloguser
der Benutzer, unter dem der Logger ausgeführt wird. (Die Protokollierung wird in Kürze erklärt.)fghack
, obwohl dies einen Kompromiss darstellt: Sie können das Programm nicht mehr mit steuernsvc
.run
Skript, um sicherzustellen, dass es das tut, was Sie möchten. Möglicherweise müssen Siesleep
oben einen Anruf tätigen, wenn Sie erwarten, dass Ihr Dienst häufig beendet wird./service
, der auf Ihr Dienstverzeichnis verweist. (Legen Sie keine Dienstverzeichnisse direkt in das Verzeichnis ein. Dadurch/service
wird es schwieriger, den Dienst vonsvscan
der Uhr zu entfernen .)Protokollierung
mkservice
).svscan
kümmert sich um das Senden von Protokollnachrichten an den Protokollierungsdienst.mkservice
erstellt automatisch gedrehte Protokolldateien mit Zeitstempel imlog/main
Verzeichnis. Die aktuelle Protokolldatei wird aufgerufencurrent
.tai64nlocal
werden die Zeitstempel in ein für Menschen lesbares Format übersetzt. (TAI64N ist ein 64-Bit-Atomzeitstempel mit einer Nanosekundenzahl.)Dienstleistungen kontrollieren
svstat
diese Option , um den Status eines Dienstes abzurufen. Beachten Sie, dass der Protokollierungsdienst unabhängig ist und einen eigenen Status hat.svc
. Verwenden Sie beispielsweise Folgendes, um Ihren Dienst neu zu startensvc -t /service/some-service-name
.-t
bedeutet "sendenSIGTERM
".-h
(SIGHUP
),-a
(SIGALRM
),-1
(SIGUSR1
),-2
(SIGUSR2
) und-k
(SIGKILL
).-d
. Sie können auch verhindern, dass ein Dienst beim Start automatisch gestartet wird, indem Sie eine Datei mit dem Namendown
im Dienstverzeichnis erstellen .-u
. Dies ist nur erforderlich, wenn Sie es zuvor heruntergefahren haben (oder so eingerichtet haben, dass es nicht automatisch startet).-x
. Wird normalerweise auch verwendet,-d
um den Dienst zu beenden. Dies ist die übliche Methode, um das Entfernen eines Dienstes zuzulassen. Sie müssen jedoch zuerst die Verknüpfung des Dienstes aufheben/service
, da sonstsvscan
der Supervisor neu gestartet wird. Wenn Sie Ihren Dienst mit einem Protokollierungsdienst (mkservice -l
) erstellt haben, müssen Sie auch den Protokollierungs-Supervisor (z. B.svc -dx /var/lib/svscan/some-service-name/log
) beenden , bevor Sie das Dienstverzeichnis entfernen.Zusammenfassung
Vorteile:
init
werden.Nachteile:
svc
und können die Ausführungsskripte nicht direkt ausführen (da sie dann nicht unter der Kontrolle des Supervisors stehen würden).supervise
Prozessen in Ihrer Prozesstabelle.)Alles in allem denke ich, dass Daemontools ein hervorragendes System für Ihre Bedürfnisse ist. Ich freue mich über alle Fragen zur Einrichtung und Wartung.
quelle
supervise
Der Supervisor kümmert sich um den Neustart aller Dienste, die beendet werden. Es wartet eine Sekunde zwischen den Restars; Wenn dies nicht genug Zeit für Sie ist, legen Sie oben im Service-Run-Skript einen Ruhezustand fest.supervise
wird selbst unterstützt vonsvscan
. Wenn ein Supervisor stirbt, wird er neu gestartet. 2b.svscan
wird von unterstütztinit
, das beisvscan
Bedarf automatisch neu gestartet wird. 2c. Wenn Ihrinit
aus irgendeinem Grund stirbt, sind Sie trotzdem geschraubt. :-Psvstat
undsvc
arbeiten können.Ich denke, Sie möchten es vielleicht versuchen
start-stop-daemon(8)
. Beispiele finden Sie in den Skripten/etc/init.d
einer Linux-Distribution. Es kann gestartete Prozesse über die aufgerufene Befehlszeile oder die PID-Datei finden, sodass es allen Ihren Anforderungen entspricht, außer dass es ein Watchdog für Ihr Skript ist. Sie können jedoch jederzeit ein anderes Daemon-Watchdog-Skript starten, das Ihr Skript bei Bedarf neu startet.quelle
start-stop-daemon
, auch nicht (ab 10.9).start-stop-daemon
ist aber noch am Leben und tritt unter Linux an; Aber nachdem ich die Antwort stackoverflow.com/a/525406/45375 gelesen hatte, wurde mir klar, dass OSX sein eigenes Ding macht :launchd
.Sie sollten sich daemonize ansehen . Es ermöglicht das Erkennen einer zweiten Kopie (verwendet jedoch den Dateisperrmechanismus). Es funktioniert auch auf verschiedenen UNIX- und Linux-Distributionen.
Wenn Sie Ihre Anwendung automatisch als Daemon starten müssen, müssen Sie ein entsprechendes Init-Skript erstellen.
Sie können die folgende Vorlage verwenden:
quelle
killproc
im Stopp-Teil nicht: Wenn Sie einen Prozess hattenjava
, der beispielsweise ausgeführt wurde,killproc
werden auch alle anderen Java-Prozesse beendet.$corelimit >/dev/null 2>&1 ; $*
Ich bezweifle, dass es irgendetwasAlternativ zu dem bereits erwähnten
daemonize
unddaemontools
gibt es den Daemon- Befehl des libslack-Pakets.daemon
ist ziemlich konfigurierbar und kümmert sich um all die mühsamen Daemon-Dinge wie automatischen Neustart, Protokollierung oder Pidfile-Behandlung.quelle
Wenn Sie OS X speziell verwenden, sollten Sie sich die Funktionsweise von launchd ansehen. Es wird automatisch überprüft, ob Ihr Skript ausgeführt wird, und es gegebenenfalls neu gestartet. Es enthält auch alle Arten von Planungsfunktionen usw. Es sollte sowohl die Anforderungen 1 als auch 2 erfüllen.
Um sicherzustellen, dass nur eine Kopie Ihres Skripts ausgeführt werden kann, müssen Sie eine PID-Datei verwenden. Im Allgemeinen schreibe ich eine Datei in /var/run/.pid, die eine PID der aktuell ausgeführten Instanz enthält. Wenn die Datei beim Ausführen des Programms vorhanden ist, wird überprüft, ob die PID in der Datei tatsächlich ausgeführt wird (das Programm ist möglicherweise abgestürzt oder hat auf andere Weise vergessen, die PID-Datei zu löschen). Wenn ja, brechen Sie ab. Wenn nicht, starten Sie die Ausführung und überschreiben Sie die PID-Datei.
quelle
Daemontools ( http://cr.yp.to/daemontools.html ) ist eine Reihe von Hardcore-Dienstprogrammen, die von DJ Bernstein geschrieben wurden. Ich habe dies mit einigem Erfolg verwendet. Das ärgerliche daran ist, dass keines der Skripte beim Ausführen sichtbare Ergebnisse zurückgibt - nur unsichtbare Rückkehrcodes. Aber sobald es läuft, ist es kugelsicher.
quelle
Holen Sie sich zuerst
createDaemon()
von http://code.activestate.com/recipes/278731/Dann der Hauptcode:
quelle
Dies ist eine Arbeitsversion mit einem Beispiel, das Sie in ein leeres Verzeichnis kopieren und ausprobieren können (nach der Installation der CPAN-Abhängigkeiten Getopt :: Long , File :: Spec , File :: Pid und IPC :: System: : Einfach - alles ziemlich normal und für jeden Hacker sehr zu empfehlen: Sie können sie alle gleichzeitig installieren mit
cpan <modulename> <modulename> ...
).keepAlive.pl:
example.pl:
Jetzt können Sie das obige Beispiel aufrufen mit:
./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3
und die Dateipidfile
wird erstellt, und Sie sehen die Ausgabe:quelle
Sie können auch Monit ausprobieren . Monit ist ein Dienst, der andere Dienste überwacht und darüber berichtet. Während es hauptsächlich verwendet wird, um (per E-Mail und SMS) über Laufzeitprobleme zu informieren, kann es auch das tun, was die meisten anderen Vorschläge hier befürwortet haben. Es kann Programme automatisch (neu) starten und stoppen, E-Mails senden, andere Skripte initiieren und ein Ausgabeprotokoll führen, das Sie abrufen können. Außerdem habe ich festgestellt, dass es einfach zu installieren und zu warten ist, da es eine solide Dokumentation gibt.
quelle
Sie könnten versuchen, unsterblich Es handelt sich um einen plattformübergreifenden * nix-Supervisor (OS Agnostic).
Für einen schnellen Versuch unter macOS:
Wenn Sie FreeBSD über die Ports oder pkg verwenden:
Für Linux durch Herunterladen der vorkompilierten Binärdateien oder von der Quelle: https://immortal.run/source/
Sie können es entweder so verwenden:
Oder durch eine Konfigurations-YAML- Datei, die Ihnen weitere Optionen bietet, zum Beispiel:
Wenn Sie auch die Standardfehlerausgabe in einer separaten Datei speichern möchten, können Sie Folgendes verwenden:
quelle
Ich habe eine Reihe von Verbesserungen an der anderen Antwort vorgenommen .
sleep
)-h
eval
, sodass Sie jede Art von Shell-Skript als Zeichenfolge erstellen können, die als letztes Argument (oder nachfolgende Argumente) an dieses Skript , damit es dämonisiert werden kann-lt
statt<
Hier ist das Skript:
Verwendung:
Beachten Sie, dass beim Ausführen dieses Skripts aus verschiedenen Verzeichnissen möglicherweise unterschiedliche PID-Dateien verwendet werden und keine vorhandenen laufenden Instanzen erkannt werden. Da es so konzipiert ist, dass es kurzlebige Befehle ausführt und neu startet, die über ein Argument bereitgestellt werden, kann nicht festgestellt werden, ob bereits etwas gestartet wurde, denn wer soll sagen, ob es sich um denselben Befehl handelt ? oder nicht? Um diese Durchsetzung zu verbessern, indem nur eine einzige Instanz von etwas ausgeführt wird, ist eine situationsspezifische Lösung erforderlich.
Damit es als richtiger Daemon fungiert, müssen Sie (mindestens) nohup verwenden, wie in der anderen Antwort erwähnt. Ich habe keine Anstrengungen unternommen, um den Signalen, die der Prozess möglicherweise empfängt, eine gewisse Widerstandsfähigkeit zu verleihen.
Ein weiterer Punkt, den Sie beachten sollten, ist, dass das Töten dieses Skripts (wenn es von einem anderen Skript aufgerufen wurde, das getötet wurde, oder mit einem Signal) möglicherweise nicht erfolgreich ist, um das Kind zu töten, insbesondere wenn das Kind noch ein anderes Skript ist. Ich bin mir nicht sicher, warum das so ist, aber es scheint etwas mit der Funktionsweise zu
eval
tun zu haben, was für mich mysteriös ist. Es kann daher ratsam sein, diese Zeile durch etwas zu ersetzen, das nur einen einzigen Befehl akzeptiert, wie in der anderen Antwort.quelle