Я столкнулся с этой проблемой, когда пыталсяответить на вопрос на Stackoverflow.
При завершении работы Ubuntu 12.04 отправляет SIGTERM
всем процессам и ждет максимум 10 секунд, прежде чем завершить их с помощью SIGKILL
(если они не были завершены раньше). Мой ответ на SO даже содержит скрипт Python, который проверяет это поведение. Скрипт запускается в терминале, отправляется в фоновый режим, а затем терминал отрекается от него. При получении SIGTERM
скрипт просто продолжает работать и непрерывно выводит в файл, как долго он работаетпослеполучение SIGTERM
.
Однако в Ubuntu 16.04 скрипт немедленно завершается при завершении работы (сообщение не SIGTERM
регистрируется).
Я гуглил некоторое время, но ничего полезного не нашел. Неужели никто не сталкивался с этим критическим изменением для текущего релиза LTS?
Вот сценарийsignaltest.py
import signal
import time
stopped = False
out = open('log.txt', 'w')
def stop(sig, frame):
global stopped
stopped = True
out.write('caught SIGTERM\n')
out.flush()
signal.signal(signal.SIGTERM, stop)
while not stopped:
out.write('running\n')
out.flush()
time.sleep(1)
stop_time = time.time()
while True:
out.write('%.4fs after stop\n' % (time.time() - stop_time))
out.flush()
time.sleep(0.1)
Скрипт использует файл log.txt
в текущем каталоге для всех выходных данных. Он имеет цикл, который печатает «running» каждую секунду. Получение SIGTERM
прерывает цикл и запускает другой цикл, который печатает секунды, прошедшие с момента получения SIGTERM
.
Скрипт запускается из терминала и отсоединен с помощью disown
:
python signaltest.py &
disown
Просто быть чистым:Это не дубликатUbuntu не отправляет SIGTERM при завершении работы. Вопрос касается настольных приложений, и ответы тоже не подходят.
решение1
systemd (в отличие от upstart в более ранних версиях Ubuntu) дополнительно отправляет SIGHUP при завершении работы (и ждет 90 с вместо 10 с перед отправкой SIGKILL
). Я предлагаю игнорировать SIGHUP
или обрабатывать SIGTERM
и SIGHUP
тем же (идемпотентным) способом.
Модифицированный тестовый сценарий можно изменить следующим образом:
import signal
import time
stopped = False
out = open('log.txt', 'w')
def stop(sig, frame):
global stopped
stopped = True
out.write('caught SIGTERM\n')
out.flush()
def ignore(sig, frsma):
out.write('ignoring signal %d\n' % sig)
out.flush()
signal.signal(signal.SIGTERM, stop)
signal.signal(signal.SIGHUP, ignore)
while not stopped:
out.write('running\n')
out.flush()
time.sleep(1)
stop_time = time.time()
while True:
out.write('%.4fs after stop\n' % (time.time() - stop_time))
out.flush()
time.sleep(0.1)