> Как реализовать graceful shutdown в Go? (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Black Wall Group (BWG)

Стек: Go

> Пример ответа

Graceful shutdown в Go реализуется через перехват сигналов ОС (SIGINT, SIGTERM) и корректное завершение работы сервера или воркеров. Основной подход - использование контекста с отменой и sync.WaitGroup.

Пример для HTTP-сервера:

GO
package main
import (
"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 := <-quit
log.Printf("Received signal: %v", sig)
// Создаем контекст с таймаутом для graceful shutdown
ctx, 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:

GO
func worker(ctx context.Context, wg *sync.WaitGroup, id int) {
defer wg.Done()
for {
select {
case <-ctx.Done():
log.Printf("Worker %d stopping", id)
return
default:
// Выполнение работы
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
var wg sync.WaitGroup
for 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)
<-sig
cancel() // Отправляем сигнал остановки всем воркерам
wg.Wait() // Ждем завершения
log.Println("All workers stopped")
}

Ключевые моменты:

  • Используйте буферизированный канал для сигналов (размер 1), чтобы избежать потери сигнала.
  • Всегда задавайте таймаут для Shutdown, чтобы сервер не завис навсегда.
  • Для воркеров используйте select с ctx.Done() для проверки отмены.
  • sync.WaitGroup гарантирует, что все горутины завершатся до выхода из программы.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью