Go

How do you gracefully shut down a service that uses channels and goroutines?

Question 216HardGo 1.22 to 1.25
func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()

	jobs := make(chan Job, 100)
	var wg sync.WaitGroup
	for range 4 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := range jobs { // drains the remaining jobs, then exits
				j.Run()
			}
		}()
	}

	go produce(ctx, jobs) // stops producing when ctx is done, then close(jobs)

	<-ctx.Done()
	log.Println("shutting down")

	done := make(chan struct{})
	go func() { wg.Wait(); close(done) }()
	select {
	case <-done:
		log.Println("clean exit")
	case <-time.After(10 * time.Second):
		log.Println("forced exit; workers still busy")
	}
}

The sequence: (1) catch the signal and turn it into a context; (2) stop the intake (the producer stops and closes jobs); (3) let workers drain the in-flight work via range; (4) wait with a hard deadline, using the WaitGroup-to-channel trick so the wait can go in a select. The interviewer is looking for: shutdown flows from producers to consumers, a single closer, and a bounded wait. For HTTP, also call srv.Shutdown(ctx).

More on Channels & select

All 38 Channels & select questions