Skip to content

Instantly share code, notes, and snippets.

@schaternik
Created May 19, 2025 12:43
Show Gist options
  • Select an option

  • Save schaternik/1369ef73013c5cc2a38f690bd16c3cb9 to your computer and use it in GitHub Desktop.

Select an option

Save schaternik/1369ef73013c5cc2a38f690bd16c3cb9 to your computer and use it in GitHub Desktop.

Revisions

  1. schaternik created this gist May 19, 2025.
    69 changes: 69 additions & 0 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    const (
    _shutdownPeriod = 15 * time.Second
    _shutdownHardPeriod = 3 * time.Second
    _readinessDrainDelay = 5 * time.Second
    )

    var isShuttingDown atomic.Bool

    func main() {
    // Setup signal context
    rootCtx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
    defer stop()

    // Readiness endpoint
    http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    if isShuttingDown.Load() {
    http.Error(w, "Shutting down", http.StatusServiceUnavailable)
    return
    }
    fmt.Fprintln(w, "OK")
    })

    // Sample business logic
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    select {
    case <-time.After(2 * time.Second):
    fmt.Fprintln(w, "Hello, world!")
    case <-r.Context().Done():
    http.Error(w, "Request cancelled.", http.StatusRequestTimeout)
    }
    })

    // Ensure in-flight requests aren't cancelled immediately on SIGTERM
    ongoingCtx, stopOngoingGracefully := context.WithCancel(context.Background())
    server := &http.Server{
    Addr: ":8080",
    BaseContext: func(_ net.Listener) context.Context {
    return ongoingCtx
    },
    }

    go func() {
    log.Println("Server starting on :8080.")
    if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
    panic(err)
    }
    }()

    // Wait for signal
    <-rootCtx.Done()
    stop()
    isShuttingDown.Store(true)
    log.Println("Received shutdown signal, shutting down.")

    // Give time for readiness check to propagate
    time.Sleep(_readinessDrainDelay)
    log.Println("Readiness check propagated, now waiting for ongoing requests to finish.")

    shutdownCtx, cancel := context.WithTimeout(context.Background(), _shutdownPeriod)
    defer cancel()
    err := server.Shutdown(shutdownCtx)
    stopOngoingGracefully()
    if err != nil {
    log.Println("Failed to wait for ongoing requests to finish, waiting for forced cancellation.")
    time.Sleep(_shutdownHardPeriod)
    }

    log.Println("Server shut down gracefully.")
    }