Building a Web Server in Go with Graceful Shutdown

Building a Web Server in Go with Graceful Shutdown

ยท

3 min read

Introduction

Go, often referred to as Golang, is a powerful language known for its efficiency and simplicity. One of its strengths lies in building high-performance web servers. In this tutorial, we will explore how to build a web server in Go and implement a graceful shutdown mechanism. Graceful shutdown allows a server to complete ongoing requests before shutting down, ensuring a smooth user experience and preventing data loss.

Use Case: Go for Web Servers

Why Go for Web Servers?

  • Performance: Go is a compiled language, resulting in fast execution times.

  • Concurrency: Go's goroutines make handling multiple requests simultaneously efficient and straightforward.

  • Simplicity: Go's syntax is clean and easy to learn, making it a great choice for both beginners and experienced developers.

Graceful Shutdown Use Case

  • User Experience: Ensures that ongoing requests are not abruptly terminated, providing a better user experience.

  • Data Integrity: Prevents data corruption by allowing operations to complete.

  • Resource Management: Helps in releasing resources like database connections gracefully.

Importance of httprouter Package

httprouter is a lightweight and efficient HTTP request router for Go. It is faster than the default http.ServeMux and supports dynamic routing with URL parameters, making it ideal for building RESTful APIs.

Code Explanation

package main

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

    "github.com/julienschmidt/httprouter"
)

func newRouter() *httprouter.Router {
    mux := httprouter.New()
    mux.GET("/welcomepage", getchannelstats())
    return mux
}

func getchannelstats() httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        w.Write([]byte("Welcome!"))
    }
}

func main() {
    srv := &http.Server{
        Addr:    ":8000",
        Handler: newRouter(),
    }

    idleconnclosed := make(chan struct{})
    go func() {
        sigint := make(chan os.Signal, 1)
        signal.Notify(sigint, os.Interrupt)
        signal.Notify(sigint, syscall.SIGTERM)
        <-sigint

        log.Println("service interrupt received")
        ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
        defer cancel()

        if err := srv.Shutdown(ctx); err != nil {
            log.Printf("http server shutdown error:%v", err)
        }

        log.Println("Shutdown Complete")
        close(idleconnclosed)
    }()

    log.Println("Starting server on port 8000")
    if err := srv.ListenAndServe(); err != nil {
        if !errors.Is(err, http.ErrServerClosed) {
            log.Fatalf("fatal http server failed to start:%v", err)
        }
    }

    <-idleconnclosed
    log.Println("Service Stop")
}

Explanation:

  • Router Setup:

    • We use the httprouter package to create a new router and define the route /welcomepage. The handler function getchannelstats responds with "Welcome!" when this endpoint is accessed.
  • HTTP Server:

    • An HTTP server is configured with the address :8000 and our router as the handler.
  • Graceful Shutdown:

    • A goroutine listens for interrupt signals (os.Interrupt and syscall.SIGTERM). When a signal is received, it initiates a graceful shutdown, allowing the server to complete any ongoing requests within a 60-second timeout.

    • The server's shutdown process is managed using a context with a timeout to ensure it doesn't hang indefinitely.

  • Main Function:

    • The main function starts the server and waits for it to serve requests. If the server encounters an error that isn't related to it being intentionally closed (http.ErrServerClosed), it logs a fatal error.

    • After the server is shut down gracefully, it logs "Service Stop" indicating the process is complete.

Running the Code

  1. Initialize a Go module:

     go mod init nameofmodule
    
  2. Download dependencies:

     go mod tidy
    
  3. Run the server:

     go run main.go
    

Output in Browser:

Output on Server Forced Stop:

  • If you forcefully stop the server (e.g., by pressing Ctrl+C), you will see the following log messages:

      service interrupt received
      Shutdown Complete
      Service Stop
    

This ensures that the server has gracefully shut down, completing any ongoing requests before termination.

Did you find this article valuable?

Support NavyaDevops by becoming a sponsor. Any amount is appreciated!

ย