Go Context Deadlines
A context deadline is a fixed moment at which a context ends itself. Work that holds the context can ask Err which ending happened.
A past deadline ends the context at once
The deadline sits in the year 2020, long before the program runs. Err reports the missed deadline right away.
package main
import (
"context"
"fmt"
"time"
)
func main() {
past := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
ctx, cancel := context.WithDeadline(context.Background(), past)
defer cancel()
fmt.Println(ctx.Err())
fmt.Println(ctx.Err() == context.DeadlineExceeded)
}An early cancel beats a later deadline
The timeout gives the context a full hour. The cancel call runs first, so it decides the error.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
cancel()
fmt.Println(ctx.Err())
}A worker stops on an expired context
The worker waits in a select on Done. The deadline already passed, so the worker prints its stopped line at once.
package main
import (
"context"
"fmt"
"sync"
"time"
)
func worker(ctx context.Context, wg *sync.WaitGroup) {
defer wg.Done()
select {
case <-ctx.Done():
fmt.Println("Worker stopped:", ctx.Err())
}
}
func main() {
past := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
ctx, cancel := context.WithDeadline(context.Background(), past)
defer cancel()
var wg sync.WaitGroup
wg.Add(1)
go worker(ctx, &wg)
wg.Wait()
fmt.Println("Main finished.")
}Example
package main
import (
"context"
"fmt"
"time"
)
func check(name string, ctx context.Context) {
if ctx.Err() == context.DeadlineExceeded {
fmt.Println(name, "ended by deadline")
return
}
fmt.Println(name, "ended by cancel")
}
func main() {
past := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
deadlineCtx, stop := context.WithDeadline(context.Background(), past)
defer stop()
cancelCtx, cancel := context.WithCancel(context.Background())
cancel()
check("First", deadlineCtx)
check("Second", cancelCtx)
}Key points
- Use context.WithDeadline to end a context at a fixed time.
- Use context.WithTimeout to end a context after a length of time.
- A context past its deadline returns context.DeadlineExceeded from Err.
- The Done channel closes when the deadline passes, just as it does on a cancel.
- An ending that happens first decides what Err reports.
In this example, main builds two ended contexts. The first carries a deadline in the year 2020, and the second ends through a cancel call. The check helper reads Err on each one and prints which ending each context met.
Note
WithDeadline and WithTimeout both return a cancel function, and calling it frees the timer early.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Go Playground
Exercise
A context gets a WithTimeout of one hour and cancel runs right after it. What does Err print?