Ответ
Команда kill в Unix-подобных системах отправляет сигналы процессам. Вопреки названию, она не всегда "убивает" процесс, а лишь уведомляет его о событии.
Для бэкенд-разработчика наиболее важны следующие сигналы:
SIGTERM(сигнал 15): Сигнал корректного завершения. Это сигнал по умолчанию дляkill. Приложение должно перехватить этот сигнал и выполнить процедуру "graceful shutdown": закрыть сетевые соединения, завершить обработку текущих запросов, сохранить данные и т.д.kill <PID> # или kill -15 <PID>SIGKILL(сигнал 9): Сигнал принудительного завершения. Этот сигнал нельзя перехватить или проигнорировать. Ядро операционной системы немедленно завершает процесс. Используется как крайняя мера, когда процесс не отвечает наSIGTERM.kill -9 <PID>SIGHUP(сигнал 1): Сигнал для перезагрузки конфигурации. Исторически означал разрыв соединения с терминалом, но сейчас часто используется для того, чтобы дать команду процессу перечитать свои конфигурационные файлы без перезапуска.
Реализация Graceful Shutdown в Go:
В Go для обработки сигналов используется пакет os/signal. Типичный паттерн выглядит так:
import (
"context"
"os"
"os/signal"
"syscall"
)
func main() {
// ... запуск сервера или воркера ...
// Создаем канал для получения сигналов ОС
quit := make(chan os.Signal, 1)
// Уведомляем о получении SIGINT (Ctrl+C) или SIGTERM
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
// Блокируемся, пока не получим сигнал
<-quit
// ... начинаем процедуру graceful shutdown ...
// Например, вызываем server.Shutdown(ctx)
} Ответ 18+ 🔞
А, слушай, про эту команду kill в линуксе — тут вообще классика жанра, блядь! Все думают, что она сразу мочит процессы, как какой-нибудь терминатор, а на самом деле она, сука, просто вежливо стучится в дверь и говорит: «Э, дружок, может, сам завершишься? А то неудобно как-то».
Вот смотри, для нас, бэкендеров, три главных сигнала — это как три степени наказания, блядь.
SIGTERM (сигнал 15) — это как вежливый намёк, типа «братан, пора закругляться». По умолчанию kill шлёт именно его. Нормальное приложение должно его перехватить и сделать graceful shutdown: допилить текущие запросы, закрыть соединения с базой, не обосраться посреди транзакции — в общем, культурно выйти.
kill <PID>
# или, для ясности, блядь
kill -15 <PID>
SIGKILL (сигнал 9) — это уже пиздец, полный игнор любых договорённостей. Его нельзя перехватить, ядро ОС просто берёт и вырубает процесс нахуй, без предупреждения. Как молотком по башке. Используется, когда процесс совсем обнаглел и на SIGTERM отвечает молчанием, сука.
kill -9 <PID>
SIGHUP (сигнал 1) — а это хитрая жопа, ёпта. Раньше означал «тебе отключили терминал», а сейчас часто используют, чтобы сказать процессу: «Э, перечитай конфиги, я их обновил, а перезапускаться тебе лень».
А теперь, блядь, как это в Go делать, чтобы не быть мудаком и завершаться культурно?
В Go за это отвечает пакет os/signal. Смотри, типичный код выглядит так, будто мы ждём, когда нам скажут «всё, хватит»:
import (
"context"
"os"
"os/signal"
"syscall"
)
func main() {
// ... тут ты запускаешь свой сервер, воркеры и прочую хуйню ...
// Делаем канал для сигналов от ОС
quit := make(chan os.Signal, 1)
// Говорим: «Слушай, как только прилетит SIGINT (Ctrl+C) или SIGTERM — пиши в этот канал»
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
// Сидим тут, ждём, блядь, как дурачки
<-quit
// Ага, пришёл сигнал! Теперь делаем graceful shutdown:
// останавливаем сервер, закрываем соединения, сохраняем состояние...
// Например, вызываем server.Shutdown(ctx)
}
Вот и вся магия, ёпта. Главное — не забыть этот graceful shutdown реализовать, а то потом будешь как тот Герасим, который Муму утопил — совесть замучает, блядь, когда прод упадёт в самый неподходящий момент.