Created
May 19, 2025 12:43
-
-
Save schaternik/1369ef73013c5cc2a38f690bd16c3cb9 to your computer and use it in GitHub Desktop.
Main function handling graceful shutdown
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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.") | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment