Skip to main content

Command Palette

Search for a command to run...

Building a Web Server in Go with Graceful Shutdown

Updated
3 min read
Building a Web Server in Go with Graceful Shutdown
N

👋 Welcome to my Hashnode profile! I'm a passionate technologist with expertise in AWS, DevOps, Kubernetes, Terraform, Datree, and various cloud technologies. Here's a glimpse into what I bring to the table: 🌟 Cloud Aficionado: I thrive in the world of cloud technologies, particularly AWS. From architecting scalable infrastructure to optimizing cost efficiency, I love diving deep into the AWS ecosystem and crafting robust solutions. 🚀 DevOps Champion: As a DevOps enthusiast, I embrace the culture of collaboration and continuous improvement. I specialize in streamlining development workflows, implementing CI/CD pipelines, and automating infrastructure deployment using modern tools like Kubernetes. ⛵ Kubernetes Navigator: Navigating the seas of containerization is my forte. With a solid grasp on Kubernetes, I orchestrate containerized applications, manage deployments, and ensure seamless scalability while maximizing resource utilization. 🏗️ Terraform Magician: Building infrastructure as code is where I excel. With Terraform, I conjure up infrastructure blueprints, define infrastructure-as-code, and provision resources across multiple cloud platforms, ensuring consistent and reproducible deployments. 🌳 Datree Guardian: In my quest for secure and compliant code, I leverage Datree to enforce best practices and prevent misconfigurations. I'm passionate about maintaining code quality, security, and reliability in every project I undertake. 🌐 Cloud Explorer: The ever-evolving cloud landscape fascinates me, and I'm constantly exploring new technologies and trends. From serverless architectures to big data analytics, I'm eager to stay ahead of the curve and help you harness the full potential of the cloud. Whether you need assistance in designing scalable architectures, optimizing your infrastructure, or enhancing your DevOps practices, I'm here to collaborate and share my knowledge. Let's embark on a journey together, where we leverage cutting-edge technologies to build robust and efficient solutions in the cloud! 🚀💻

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.

More from this blog

NavyaDevops

78 posts

DevOps Engineer with advanced skills in cloud technologies. Proven track record in optimizing development and deployment processes. Dedicated to innovation and scalability in software development.