DEV Community

loading...

Graceful shutdown

Matija Krajnik
QA automation engineer experienced in writing GUI automated tests for Web and Mobile apps, Web REST API automated tests, load/performance tests, and developing custom testing tools from scratch.
Originally published at letscode.blog Updated on ・2 min read

If our server process gets signal to shut it down, we would like to finish the request currently handling before that happens. For that we will use graceful shutdown provided by Gin. This example is explained in detail on Gin GitHub with description in comments, so i will not go into details myself. Our internal/server/server.go will now look like this:

package server

import (
  "context"
  "errors"
  "net/http"
  "os"
  "os/signal"
  "rgb/internal/conf"
  "rgb/internal/database"
  "rgb/internal/store"
  "syscall"
  "time"

  "github.com/rs/zerolog/log"
)

const InternalServerError = "Something went wrong!"

func Start(cfg conf.Config) {
  jwtSetup(cfg)

  store.SetDBConnection(database.NewDBOptions(cfg))

  router := setRouter()

  server := &http.Server{
    Addr:    cfg.Host + ":" + cfg.Port,
    Handler: router,
  }

  // Initializing the server in a goroutine so that
  // it won't block the graceful shutdown handling below
  go func() {
    if err := server.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) {
      log.Error().Err(err).Msg("Server ListenAndServe error")
    }
  }()

  // Wait for interrupt signal to gracefully shutdown the server with
  // a timeout of 5 seconds.
  quit := make(chan os.Signal)
  // kill (no param) default send syscall.SIGTERM
  // kill -2 is syscall.SIGINT
  // kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
  signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
  <-quit
  log.Info().Msg("Shutting down server...")

  // The context is used to inform the server it has 5 seconds to finish
  // the request it is currently handling
  ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  defer cancel()

  if err := server.Shutdown(ctx); err != nil {
    log.Fatal().Err(err).Msg("Server forced to shutdown")
  }

  log.Info().Msg("Server exiting.")
}
Enter fullscreen mode Exit fullscreen mode

Discussion (0)