What does this print?
Question 263HardGo 1.22 to 1.25
func main() {
parent, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
child, cancelChild := context.WithCancel(parent)
defer cancelChild()
<-child.Done()
fmt.Println(child.Err())
fmt.Println(errors.Is(child.Err(), context.DeadlineExceeded))
fmt.Println(context.Cause(child) == context.DeadlineExceeded)
cancelChild()
fmt.Println(child.Err())
}
Output:
context deadline exceeded
true
true
context deadline exceeded
The child is a plain WithCancel, but when the parent times out, propagation cancels the child with the parent's error and cause, which is DeadlineExceeded. So the child reports "deadline exceeded" even though it has no timer of its own. The later cancelChild() does nothing: cancellation is first-write-wins, so Err() never changes once set.
What the interviewer is looking for: knowing that the error comes from whichever cancellation happened first anywhere up the chain, and that Err() is fixed after the first cancel.
More on Context
- Q261Why must you always call the CancelFunc, even if the operation finished successfully? What leaks if you don't?
- Q262WithTimeout vs WithDeadline: what is the difference, and what happens when a child asks for a later deadline than its parent?
- Q264What values can ctx.Err() return, and how should you check them?
- Q265What is WithCancelCause, and how does ctx.Err() differ from context.Cause(ctx)?
- Q266What does this print? (WithTimeoutCause and its cancel function)
- Q267Why should context keys use an unexported custom type instead of a string? Show the idiomatic pattern.