Go

What does this print? (AfterFunc on already-canceled and live contexts)

Question 290HardGo 1.22 to 1.25
func main() {
	ctx, cancel := context.WithCancel(context.Background())
	cancel()

	done := make(chan struct{})
	stop := context.AfterFunc(ctx, func() {
		fmt.Println("callback ran")
		close(done)
	})
	<-done
	fmt.Println(stop())

	ctx2, cancel2 := context.WithCancel(context.Background())
	stop2 := context.AfterFunc(ctx2, func() { fmt.Println("never") })
	fmt.Println(stop2())
	fmt.Println(stop2())
	cancel2()
	time.Sleep(10 * time.Millisecond)
	fmt.Println("end")
}

Output:

callback ran
false
true
false
end
  • Registering on a context that is already done starts f at once in a new goroutine. By the time we call stop(), f has started, so it returns false.
  • On a live context, the first stop2() removes the registration and returns true. The second call returns false because it was already stopped. After that, cancel2() has nothing to run, so "never" is never printed.
  • f always runs on its own goroutine, never on the goroutine that calls cancel. So a slow or blocking callback cannot stall the canceler, but you need your own synchronization (the done channel here) to know when it has finished.

What the interviewer is looking for: that false is ambiguous (already started, or already stopped), and that stop never waits for f.

More on Context

All 35 Context questions