Arrestare con garbo i server Web di Go

Dec 19 2022
La chiusura ordinata è un'attività comune per i server Web ed è una caratteristica molto importante. Indagheremo su come farlo a Golang.
https://github.com/MariaLetta/free-gophers-pack

La chiusura ordinata è un'attività comune per i server Web ed è una caratteristica molto importante. Indagheremo su come farlo a Golang. Immergiamoci.

Cos'è l'arresto con grazia?

Se il tuo server web è in attesa che le tue richieste attive vengano gestite prima di arrestare il server, significa che stai arrestando con garbo il server.

Perché è importante?

Immagina di visitare un negozio. Chiudono alle 22:00. E sei dentro alle 21:55 e quando sono le 22:00. chiuderanno il negozio, non accetteranno nuovi clienti ma aiuteranno i clienti all'interno e li serviranno poi torneranno a casa. Stanno chiudendo con garbo il negozio.

È la stessa idea per i server web. Ricevi un segnale per spegnere il server web. Quindi non accetterai nuove richieste, servirai le richieste attive e quindi chiuderai il server web.

Esempio

Creiamo un server web in esecuzione sulla porta 8000. Quindi creiamo una goroutine per eseguire il server web in modo che non blocchi il codice.

Esecuzione del server web

srv.ListenAndServe eseguirà il server Web sulla porta 8000. In caso di errore, registreremo l'errore.

Potresti notare ulteriori errori di controllo.Is(err, http.ErrServerClosed). Quando spegni o chiudi il server, http.ErrServerClosed verrà restituito quindi non è un errore durante l'esecuzione del server Web, quindi ignorerò l'errore.

Perché utilizzare il canale?

La ricezione del richiamo da un canale è un'operazione di blocco. <-quit bloccherà il programma

Definisco un os.Signalcanale per poter bloccare l'applicazione fino a ricevere un segnale dal sistema operativo. signal.Notifyinvierà un segnale al quitcanale quando il programma viene interrotto. Puoi farlo con ctrl + c.

Perché il timeout del contesto?

Immagina di avere un bug nel nostro codice e di chiudere il server per utilizzare la nuova versione che corregge questo bug. Immagine questo bug ci fa gestire una delle nostre richieste attive in pochi minuti. Quindi non dovremmo aspettare così tanto. Nel codice qui sotto, dico, hey non aspettare più di 30 secondi. Spegnere il server anche se ci sono richieste attive dopo 30 secondi. Questo è il motivo per cui utilizzare il contesto con timeout. srv.Shutdownspegnerà con garbo il server in 30 secondi.

package main

import (
 "context"
 "errors"
 "log"
 "net/http"
 "os"
 "os/signal"
 "time"
)

func main() {
 srv := &http.Server{
  Addr: ":8000",
 }
 go func() {
  if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
   log.Fatal(err)
  }
 }()
 quit := make(chan os.Signal, 1)
 signal.Notify(quit, os.Interrupt)
 <-quit
 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 defer cancel()
 if err := srv.Shutdown(ctx); err != nil {
  log.Fatal(err)
 }
}