Nehmen wir an, wir haben einen so trivialen Daemon in Python geschrieben:
def mainloop():
while True:
# 1. do
# 2. some
# 3. important
# 4. job
# 5. sleep
mainloop()
und wir dämonisieren es, indem wir start-stop-daemon
standardmäßig das Signal SIGTERM
( TERM
) senden --stop
.
Nehmen wir an, der aktuell ausgeführte Schritt ist #2
. Und in diesem Moment senden wir ein TERM
Signal.
Was passiert ist, dass die Ausführung sofort beendet wird.
Ich habe festgestellt, dass ich das Signalereignis mit verarbeiten kann, signal.signal(signal.SIGTERM, handler)
aber die Sache ist, dass es immer noch die aktuelle Ausführung unterbricht und die Steuerung an übergibt handler
.
Meine Frage ist also: Ist es möglich, die aktuelle Ausführung nicht zu unterbrechen, sondern das TERM
Signal in einem getrennten Thread (?) Zu verarbeiten, damit ich es shutdown_flag = True
so einstellen konnte, dass ich die Möglichkeit mainloop()
hatte, ordnungsgemäß anzuhalten?
quelle
signalfd
ich die LieferungSIGTERM
an den Prozess verwendet und ausgeblendet habe.Antworten:
Eine klassenbasierte Clean-to-Use-Lösung:
quelle
False
Wert wird nur einmal festgelegt und kann dann nur von False auf True geändert werden, sodass Mehrfachzugriff kein Problem darstellt.Erstens bin ich mir nicht sicher, ob Sie einen zweiten Thread benötigen, um das festzulegen
shutdown_flag
.Warum nicht direkt im SIGTERM-Handler einstellen?
Eine Alternative besteht darin, eine Ausnahme vom
SIGTERM
Handler auszulösen, die über den Stapel weitergegeben wird. Vorausgesetzt, Sie haben eine ordnungsgemäße Ausnahmebehandlung (z. B. mitwith
/contextmanager
undtry: ... finally:
Blöcken), sollte dies ein recht elegantes Herunterfahren sein, ähnlich wie bei Ctrl+CIhrem Programm.Beispielprogramm
signals-test.py
:Nun sehen Sie das Ctrl+CVerhalten:
Diesmal sende ich es
SIGTERM
nach 4 Iterationen mitkill $(ps aux | grep signals-test | awk '/python/ {print $2}')
:Dieses Mal aktiviere ich meinen benutzerdefinierten
SIGTERM
Handler und sende ihnSIGTERM
:quelle
Ich denke, Sie sind einer möglichen Lösung nahe.
Ausführen
mainloop
in einem separaten Thread und erweitern sie mit der Eigenschaftshutdown_flag
. Das Signal kannsignal.signal(signal.SIGTERM, handler)
im Haupt-Thread abgefangen werden (nicht in einem separaten Thread). Der Signalhandler sollteshutdown_flag
auf True gesetzt sein und warten, bis der Thread beendet istthread.join()
quelle
Hier ist ein einfaches Beispiel ohne Threads oder Klassen.
quelle
Basierend auf den vorherigen Antworten habe ich einen Kontextmanager erstellt, der vor Sigint und Sigterm schützt.
quelle
Am einfachsten für mich gefunden. Hier ein Beispiel mit Gabel zur Verdeutlichung, dass dieser Weg für die Flusskontrolle nützlich ist.
quelle
Die einfachste Lösung, die ich gefunden habe und die sich von den obigen Antworten inspirieren lässt, ist
quelle