package main import ( "context" "fmt" "os" "os/signal" "sync" "syscall" "time" ) // simulateWork represents a goroutine doing some work that needs to be gracefully stopped. func simulateWork(ctx context.Context, id int) { for { select { case <-time.After(time.Millisecond * 200): // Simulate work chunk fmt.Printf("Worker %d: Doing work... ", id) case <-ctx.Done(): fmt.Printf("Worker %d: Shutting down gracefully. Reason: %v ", id, ctx.Err()) return // Exit the goroutine } } } func main() { // Create a context that can be cancelled ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Ensure cancellation is called eventually var wg sync.WaitGroup // Start multiple worker goroutines for i := 1; i <= 3; i++ { wg.Add(1) go func(workerID int) { defer wg.Done() simulateWork(ctx, workerID) }(i) } // Set up a channel to listen for OS signals sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) fmt.Println("Server started. Press Ctrl+C to initiate graceful shutdown.") // Block until a signal is received sig := <-sigChan fmt.Printf(" Received signal: %v. Initiating graceful shutdown... ", sig) // Cancel the context, signaling all goroutines to stop cancel() // Give goroutines a chance to finish current tasks (optional, with timeout) done := make(chan struct{}) go func() { wg.Wait() // Wait for all worker goroutines to finish close(done) }() select { case <-done: fmt.Println("All workers have shut down.") case <-time.After(time.Second * 5): // A timeout for graceful shutdown fmt.Println("Timeout reached. Some workers might not have finished gracefully.") } fmt.Println("Server gracefully stopped.") }