Ich habe einen Systemd Socket-aktivierten Dienst in Haskell geschrieben. Die Idee ist, dass der Dienst automatisch gestartet werden soll, wenn eine Nachricht an seinen Socket gesendet wird. Der Dienst sollte alle auf dem Socket wartenden Nachrichten verarbeiten und dann beenden.
Hinweis: Der Grund, warum der Dienst nach der Verarbeitung aller wartenden Nachrichten geschlossen werden sollte (im Gegensatz zur Ausführung für immer), ist, dass zwischen Socketaktivierungen mehrere Stunden oder Tage liegen.
deploy-trigger.socket:
%Vor%deploy-trigger.service:
%Vor%Main.hs
%Vor% Wenn kompiliert (und mit stack install
installiert), dann aktiviert durch das Senden von etwas Text an den Socket mit dem folgenden Befehl:
Das Folgende wird in das Systemd-Journal gedruckt (Ich verwende journalctl -f
, um die Logs zu sehen):
nichts anderes ist gedruckt; Der Prozess läuft für immer und maximiert alle CPU-Kerne des Computers. Warum passiert das und gibt es eine Möglichkeit, das Verhalten auf das im ersten Absatz beschriebene zu ändern?
Ändern von main
zu folgendem:
das Entfernen von forever
, stack install
ing erneut und das Senden von Text an den Socket gibt Folgendes an das Journal aus:
deploy-trigger-exe
wird dann sauber beendet. Der Nachteil ist, dass die Binärdatei anscheinend von Systemd für jede an den Socket gesendete Nachricht ausgeführt wird, was nicht wünschenswert ist.
Hinweis: Ich vermute, dass das Problem in meiner Inkompetenz in Bezug auf UNIX-Sockets begründet ist. Irgendwelche Antworten mit unterstützenden Informationen darüber, was ich falsch verstanden habe, um meine Duff-Terminologie zu korrigieren, wäre ein Bonus.
OK, zuerst in Bezug auf die fehlende Ausgabe, es ist genau wie Li-yao Xia
sagt, auf Linux-Ausgaben sind Block-gepuffert, wenn in eine Rohrleitung geschrieben.
Ändere dein main
zu
und Sie werden in journalctl -f
:
Nach dieser (erwarteten) Ausgabe hängt Ihr Programm.
Wie finde ich heraus, wo es hängt? Natürlich mit strace
(Gerüchten zufolge können 95% aller Computerprobleme mit strace
gelöst werden).
Wie wir sehen können, ist das Programm jetzt in accept sock
blockiert. Dies ist sinnvoll (weil die andere Seite nicht verbunden ist).
Eine andere Sache, über die Sie vielleicht verwirrt sind, ist, warum sie Got socket(s)
ein zweites Mal druckt.
Ich denke, Sie haben ein Missverständnis darüber, wie getActivatedSockets
funktioniert. Ich schließe damit ab, dass du forever $ getActivatedSockets >>= ...
schreibst. Dies deutet darauf hin, dass Sie erwarten, dass Sie beim zweiten Aufruf von getActivatedSockets
etwas anderes als das erste Mal zurückgeben (insbesondere vermute ich, dass Sie glauben, dass Nothing
zurückgegeben wird, nachdem die Sockets in einigen "verarbeitet" wurden) Weg).
Aber schaut euch den Code von% an. co_de% , es wird immer das gleiche Ergebnis zurückgeben (weil es nur den Inhalt einiger Umgebungsvariablen liest). Es scheint daher nicht sinnvoll zu sein, es in getActivatedSockets
einzufügen.
Du hast
geschriebenDer Dienst sollte alle auf dem Socket wartenden Nachrichten verarbeiten und dann
beenden
Um das zu erreichen, sollten Sie das forever
:
(Wenn Sie diesen geänderten Code ausprobieren, vergessen Sie nicht, das noch laufende forever
zuerst zu beenden.)
Sie erhalten:
%Vor%was ich denke, was Sie suchen.
Noch ein Tipp: Wenn Sie eine große Nachricht an den Socket senden, müssen Sie deploy-trigger-exe
durchlaufen, um alle Daten zu empfangen.
(Quick plug: Ich bin im Geschäft mit Problemen wie diesem zu helfen.)
Es scheint, dass, weil stdout
nicht mit einem Terminal verbunden ist, die kleine Ausgabe von putStrLn
gepuffert bleibt und daher nicht in den Protokollen erscheint. Dies wird behoben, indem Sie hFlush
regelmäßig aufrufen, zum Beispiel:
Tags und Links haskell sockets systemd unix-socket