Skip to content

Commit 563ab11

Browse files
authored
Refactor graceful shutdown example (#994)
Simplify server shutdown by replacing manual signal handling with `signal.NotifyContext`.
1 parent a52c582 commit 563ab11

File tree

1 file changed

+16
-29
lines changed

1 file changed

+16
-29
lines changed

_examples/graceful/main.go

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package main
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"log"
78
"net/http"
8-
"os"
99
"os/signal"
1010
"syscall"
1111
"time"
@@ -18,41 +18,28 @@ func main() {
1818
// The HTTP Server
1919
server := &http.Server{Addr: "0.0.0.0:3333", Handler: service()}
2020

21-
// Server run context
22-
serverCtx, serverStopCtx := context.WithCancel(context.Background())
21+
// Create context that listens for the interrupt signal
22+
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
23+
defer stop()
2324

24-
// Listen for syscall signals for process to interrupt/quit
25-
sig := make(chan os.Signal, 1)
26-
signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
25+
// Run server in the background
2726
go func() {
28-
<-sig
29-
30-
// Shutdown signal with grace period of 30 seconds
31-
shutdownCtx, _ := context.WithTimeout(serverCtx, 30*time.Second)
32-
33-
go func() {
34-
<-shutdownCtx.Done()
35-
if shutdownCtx.Err() == context.DeadlineExceeded {
36-
log.Fatal("graceful shutdown timed out.. forcing exit.")
37-
}
38-
}()
39-
40-
// Trigger graceful shutdown
41-
err := server.Shutdown(shutdownCtx)
42-
if err != nil {
27+
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
4328
log.Fatal(err)
4429
}
45-
serverStopCtx()
4630
}()
4731

48-
// Run the server
49-
err := server.ListenAndServe()
50-
if err != nil && err != http.ErrServerClosed {
32+
// Listen for the interrupt signal
33+
<-ctx.Done()
34+
35+
// Create shutdown context with 30-second timeout
36+
shutdownCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
37+
defer cancel()
38+
39+
// Trigger graceful shutdown
40+
if err := server.Shutdown(shutdownCtx); err != nil {
5141
log.Fatal(err)
5242
}
53-
54-
// Wait for server context to be stopped
55-
<-serverCtx.Done()
5643
}
5744

5845
func service() http.Handler {
@@ -69,7 +56,7 @@ func service() http.Handler {
6956
// Simulates some hard work.
7057
//
7158
// We want this handler to complete successfully during a shutdown signal,
72-
// so consider the work here as some background routine to fetch a long running
59+
// so consider the work here as some background routine to fetch a long-running
7360
// search query to find as many results as possible, but, instead we cut it short
7461
// and respond with what we have so far. How a shutdown is handled is entirely
7562
// up to the developer, as some code blocks are preemptible, and others are not.

0 commit comments

Comments
 (0)