Короткий ответ
Сначала проверяют, установлен ли в приложении обработчик SIGTERM и что именно он делает (возможно, зависает на внешнем вызове или ожидании соединения); если SIGTERM полностью игнорируется или обработчик завис, супервизор (systemd, оркестратор контейнеров) по истечении тайм-аута принудительно пришлёт SIGKILL.
Как это работает подробнее
SIGTERM, в отличие от SIGKILL, можно перехватить, заблокировать или проигнорировать на уровне приложения через sigaction(); если обработчик пытается, например, дождаться ответа от уже недоступной базы данных или завершить все активные соединения без тайм-аута, процесс может «зависнуть» в graceful shutdown бесконечно, пока его не остановят силой.
Пример кода
example.txt
[Service]
ExecStart=/usr/bin/myapp
KillSignal=SIGTERM
TimeoutStopSec=20
SendSIGKILL=yesЧто использовать на практике
- Практика. правильная graceful shutdown-логика должна иметь собственный внутренний тайм-аут (например, 10–30 секунд на дренаж соединений), после которого процесс завершает себя сам, не полагаясь только на внешний TimeoutStopSec в systemd или terminationGracePeriodSeconds в Kubernetes; также стоит логировать сам факт получения SIGTERM и ход graceful shutdown для диагностики зависаний.
Подводные камни
- Риск. Частая ошибка — увеличивать TimeoutStopSec/terminationGracePeriodSeconds как единственное решение проблемы долгого завершения вместо того, чтобы разобраться, почему graceful shutdown зависает (например, ждёт сетевой вызов без тайм-аута).