Нет SIGTERM до SIGKILL/ завершение работы с systemd в Ubuntu 16.04

Я столкнулся с этой проблемой, пытаясь ответить на вопрос о 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 в текущем каталоге для всего вывода. У него есть цикл, который печатает "работает" каждую секунду. получающий 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)
Другие вопросы по тегам