Подход к Graceful Shutdown в Go
И почему это не работает в Kubernetes
Артемий Рябинков
Avito
Slide 2
Slide 2 text
Что такое Graceful Shutdown и зачем он
нужен?
● Завершаемся предсказуемо
● Не теряем данные
Slide 3
Slide 3 text
https://12factor.net/disposability
Slide 4
Slide 4 text
Бесшовная выкатка
● Выкатываем новую версию сервиса
● Переключаем на неё трафик
● Отключаем старую версию сервиса
Slide 5
Slide 5 text
Время ответа Кол-во ошибок
Slide 6
Slide 6 text
Идеально: время ответа не скачет и ошибок нет!
ms
Slide 7
Slide 7 text
Как программе узнать о
необходимости завершиться?
Сигналы!
SIGTERM, SIGINT, SIGQUIT, SIGKILL
Slide 8
Slide 8 text
План
Пишем на PHP
● Слушаем сигнал
● Просим потоки завершиться
● Ждем завершения всех потоков
● Выходим из процесса
Slide 9
Slide 9 text
main
SIGTERM
Slide 10
Slide 10 text
Ловим сигнал OS
// Register signal handler
sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
syscall.SIGINT, syscall.SIGTERM)
// Wait for signal
<-sigc
Slide 11
Slide 11 text
Завершаем Goroutine
Slide 12
Slide 12 text
func main() {
done := make(chan struct{})
go listen(done)
// .. SIGTERM
close(done)
// .. wait for listen
}
Slide 13
Slide 13 text
func main() {
ctx, cancel := context.WithCancel(...)
go listen(ctx)
// .. SIGTERM
cancel()
// .. wait for listen
}
Slide 14
Slide 14 text
func listen(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
// .. do hard work
}
}
}