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 functiongetchannelstats
responds with "Welcome!" when this endpoint is accessed.
- We use the
HTTP Server:
- An HTTP server is configured with the address
:8000
and our router as the handler.
- An HTTP server is configured with the address
Graceful Shutdown:
A goroutine listens for interrupt signals (
os.Interrupt
andsyscall.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 nameofmodule
Download dependencies:
go mod tidy
Run 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.