Первый шаг к нормальному завершению работы — научить сервер слышать сигналы от операционной системы. Без этого процесс падает молча, не успев ничего сделать.
📎 Добавляем обработку сигналов
Вместо того чтобы просто запустить
http.ListenAndServe, запускаем его в горутине, а в основном потоке ждём сигнала:package main
import (
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Println("handling request...")
time.Sleep(5 * time.Second)
fmt.Fprintln(w, "done")
}
func main() {
http.HandleFunc("/", handler)
go func() {
fmt.Println("server started at :8080")
http.ListenAndServe(":8080", nil)
}()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
<-sig
fmt.Println("shutdown signal received")
fmt.Println("exit")
}
Ключевые строки:
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
<-sig
signal.Notify подписывает канал на SIGINT и SIGTERM. Когда ОС посылает один из этих сигналов, программа не падает немедленно, а получает уведомление и может выполнить финальный код.📎 В чём всё ещё проблема
Сервер теперь знает, что его просят остановиться. Но он всё равно не ждёт текущие запросы. Если обработчик в середине работы,
<-sig разблокируется и программа завершается, не дождавшись его.Осведомлённость о сигнале — это не то же самое, что graceful shutdown. Это только первый слой.
Этот паттерн уже лучше наивного варианта. Сервис перестаёт падать просто так. Но для прода нужен следующий шаг — дать текущим запросам возможность завершиться.
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoToProduction