ProgramGuru

Graceful Shutdown

Start with Graceful Shutdown

Learn graceful shutdown through an executable example, then connect the small demonstration to production code.

What you’ll learn

  • Explain the main purpose of graceful shutdown.
  • Read and run the complete Go example in this lesson.
  • Apply the concept and recognize common mistakes.

Understand the idea

Graceful shutdown stops accepting new work while allowing active requests to finish within a bounded period. http.Server.Shutdown initiates this behavior for an HTTP server.

This local example starts a server on an OS-assigned loopback port, checks one request, then shuts it down using a context with a deadline. It does not need a fixed port.

Visualize how it works

Follow this diagram before executing the example. Check where a value or decision changes what runs next.

Visual explanation for shutdownA bounded shutdown favors orderly completion.Signal receivedStep 1Stop acceptingStep 2Drain active requestsStep 3Close resourcesStep 4A bounded shutdown favors orderly completion.
A bounded shutdown favors orderly completion.

Tools, syntax and practical notes

In an executable server, capture SIGINT/SIGTERM with signal.NotifyContext and use Shutdown with a fresh bounded context. Ensure application-specific workers and database resources also stop cleanly.

Run a complete Go example

This example is a complete program. Save it as main.go or paste it into the Go Playground.

Go code

package main

import (
	"context"
	"fmt"
	"net"
	"net/http"
	"time"
)

func main() {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		panic(err)
	}
	srv := &http.Server{Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "ready") })}
	finished := make(chan error, 1)
	go func() { finished <- srv.Serve(ln) }()
	client := &http.Client{Timeout: 2 * time.Second}
	resp, err := client.Get("http://" + ln.Addr().String())
	if err != nil {
		panic(err)
	}
	fmt.Println("Status:", resp.StatusCode)
	resp.Body.Close()
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		panic(err)
	}
	fmt.Println("Stopped:", <-finished == http.ErrServerClosed)
}

Output

Status: 200
Stopped: true

Trace what the program does

The server answers the local request with 200. Shutdown causes Serve to return http.ErrServerClosed; the printed check is true. A production process also needs signal handling and a plan for background workers.

Avoid common mistakes

  • Calling Close abruptly is different from allowing active requests to finish via Shutdown.
  • Give shutdown a timeout and handle requests or background work that cannot finish within it.

Try it yourself

Add a graceful shutdown path triggered by an OS signal in a separate application, including a bounded deadline.

Tip: Edit the example above, predict the output, and run the modified code to test your reasoning.

Check your understanding

What does http.Server.Shutdown aim to do?
Choose one answer. You can try again.

Answer and explanation

Drain active HTTP requests while closing listeners

Correct. The server answers the local request with 200.

What you should remember

You have practiced Graceful Shutdown in a small, self-contained program. The important habit is to predict what runs, inspect the actual output and distinguish the language rule from the particular example.

Before continuing, make sure you can explain the program to someone who has not seen it, including the line that changes its result.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Performance and Memory Optimization →