Pass a context.Context to your goroutines to signal cancellation or timeouts, and check ctx.Done() inside the goroutine to stop work immediately. This prevents goroutines from running indefinitely after the parent operation is done.
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d stopped\n", id)
return
default:
// Do work
time.Sleep(100 * time.Millisecond)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
go worker(ctx, 1)
go worker(ctx, 2)
<-ctx.Done()
fmt.Println("All workers stopped")
}