Warum bedeutet "für immer", dass dieser Code nicht von einem Socket liest oder auf stdout druckt?

8

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:

%Vor%

Das Folgende wird in das Systemd-Journal gedruckt (Ich verwende journalctl -f , um die Logs zu sehen):

%Vor%

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:

%Vor%

das Entfernen von forever , stack install ing erneut und das Senden von Text an den Socket gibt Folgendes an das Journal aus:

%Vor%

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.

    
user4301448 28.01.2018, 22:27
quelle

2 Antworten

2

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

%Vor%

und Sie werden in journalctl -f :

sehen %Vor%

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).

%Vor%

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

geschrieben
  

Der Dienst sollte alle auf dem Socket wartenden Nachrichten verarbeiten und dann

beenden

Um das zu erreichen, sollten Sie das forever :

entfernen %Vor%

(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.)

    
nh2 01.02.2018, 13:49
quelle
3

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:

%Vor%     
Li-yao Xia 31.01.2018 16:52
quelle