> Как реализовать graceful shutdown в Go? (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Black Wall Group (BWG)
Стек: Go
> Пример ответа
Graceful shutdown в Go реализуется через перехват сигналов ОС (SIGINT, SIGTERM) и корректное завершение работы сервера или воркеров. Основной подход - использование контекста с отменой и sync.WaitGroup.
Пример для HTTP-сервера:
GOpackage mainimport ("context""log""net/http""os""os/signal""syscall""time")func main() {srv := &http.Server{Addr: ":8080"}// Канал для сигналовquit := make(chan os.Signal, 1)signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)// Запуск сервера в горутинеgo func() {log.Println("Server started")if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {log.Fatalf("Server error: %v", err)}}()// Ожидание сигналаsig := <-quitlog.Printf("Received signal: %v", sig)// Создаем контекст с таймаутом для graceful shutdownctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)defer cancel()// Завершаем сервер с уважением к активным соединениямif err := srv.Shutdown(ctx); err != nil {log.Fatalf("Server forced shutdown: %v", err)}log.Println("Server stopped gracefully")}
Для воркеров (например, обработчиков очередей) используйте context.WithCancel и sync.WaitGroup:
GOfunc worker(ctx context.Context, wg *sync.WaitGroup, id int) {defer wg.Done()for {select {case <-ctx.Done():log.Printf("Worker %d stopping", id)returndefault:// Выполнение работы}}}func main() {ctx, cancel := context.WithCancel(context.Background())var wg sync.WaitGroupfor i := 0; i < 3; i++ {wg.Add(1)go worker(ctx, &wg, i)}// Ожидание сигналаsig := make(chan os.Signal, 1)signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)<-sigcancel() // Отправляем сигнал остановки всем воркерамwg.Wait() // Ждем завершенияlog.Println("All workers stopped")}
Ключевые моменты:
- Используйте буферизированный канал для сигналов (размер 1), чтобы избежать потери сигнала.
- Всегда задавайте таймаут для
Shutdown, чтобы сервер не завис навсегда. - Для воркеров используйте
selectсctx.Done()для проверки отмены. sync.WaitGroupгарантирует, что все горутины завершатся до выхода из программы.
> Похожие задачи по Go
Что происходит с горутиной, если она пытается записать в канал после ошибки?
Что делать, если нельзя писать логи внутри функции fetch, а можно только в функции main?
Почему интерфейсы лучше размещать в месте их применения?
Куда нужно положить интерфейс, если робот реализует интерфейс?
> Похожие задачи по backend
Что происходит с горутиной, если она пытается записать в канал после ошибки?
Что делать, если нельзя писать логи внутри функции fetch, а можно только в функции main?
Почему интерфейсы лучше размещать в месте их применения?
Куда нужно положить интерфейс, если робот реализует интерфейс?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью