Давайте предположим, что у нас есть такой тривиальный демон, написанный на python:
def mainloop():
while True:
# 1. do
# 2. some
# 3. important
# 4. job
# 5. sleep
mainloop()
и мы демонизируем его, используя start-stop-daemon
который по умолчанию посылает сигнал SIGTERM
( TERM
) --stop
.
Давайте предположим, что текущий шаг выполнен #2
. И в этот самый момент мы посылаем TERM
сигнал.
То, что происходит, - то, что выполнение немедленно прекращается.
Я обнаружил, что могу обрабатывать событие сигнала с помощью, signal.signal(signal.SIGTERM, handler)
но дело в том, что он все еще прерывает текущее выполнение и передает управление handler
.
Итак, мой вопрос - возможно ли не прерывать текущее выполнение, а обрабатывать TERM
сигнал в отдельном потоке (?), Чтобы я мог установить shutdown_flag = True
так, чтобы у меня была возможность mainloop()
изящно остановиться?
источник
signalfd
и маскируя доставкуSIGTERM
процесса.Ответы:
Чистое в использовании решение на основе классов:
источник
False
Значение устанавливается только один раз, а затем он может идти только от Ложного к подлинному так множественный доступ не является проблема.Во-первых, я не уверен, что вам нужен второй поток для установки
shutdown_flag
.Почему бы не установить его непосредственно в обработчике SIGTERM?
Альтернатива - вызвать исключение из
SIGTERM
обработчика, который будет распространяться вверх по стеку. Предполагая, что у вас есть правильная обработка исключений (например, сwith
/contextmanager
иtry: ... finally:
блоками), это должно быть довольно изящное завершение работы, как если бы выCtrl+C программой.Пример программы
signals-test.py
:Теперь посмотрим на Ctrl+Cповедение:
На этот раз я отправляю его
SIGTERM
после 4 итераций сkill $(ps aux | grep signals-test | awk '/python/ {print $2}')
:На этот раз я включаю свой собственный
SIGTERM
обработчик и отправляю егоSIGTERM
:источник
Я думаю, что вы близки к возможному решению.
Выполнить
mainloop
в отдельном потоке и расширить его свойствомshutdown_flag
. Сигнал может быть пойманsignal.signal(signal.SIGTERM, handler)
в основном потоке (не в отдельном потоке). Обработчик сигнала должен установитьshutdown_flag
значение True и ждать окончания потокаthread.join()
источник
Вот простой пример без потоков или классов.
источник
Основываясь на предыдущих ответах, я создал менеджер контекста, который защищает от sigint и sigterm.
источник
Нашел самый простой способ для меня. Вот пример с вилкой для ясности, что этот способ полезен для управления потоком.
источник
Самое простое решение, которое я нашел, вдохновленный ответами выше, это
источник