Building a Web Server in Go with Graceful Shutdown

👋 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
httprouterpackage to create a new router and define the route/welcomepage. The handler functiongetchannelstatsresponds with "Welcome!" when this endpoint is accessed.
- We use the
HTTP Server:
- An HTTP server is configured with the address
:8000and our router as the handler.
- An HTTP server is configured with the address
Graceful Shutdown:
A goroutine listens for interrupt signals (
os.Interruptandsyscall.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
Initialize a Go module:
go mod init nameofmoduleDownload dependencies:
go mod tidyRun the server:
go run main.go
Output in Browser:
Open a browser and navigate to
http://localhost:8000/welcomepage.You should see the message:
Welcome!.
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.




