Lesson 16 / 26
select, Timeouts and context
Cancel work that takes too long.
Wait on several operations
select waits on several channel operations and proceeds with whichever is ready. Combined with context.Context, it implements timeouts and cancellation: a context created with context.WithTimeout or WithCancel closes its Done() channel when it expires or is cancelled, and ctx.Err() says why. Pass ctx as the first parameter through call chains (HTTP handlers, database calls) so a cancelled request stops all its work.
A query racing a deadline, run
I ran this with Go 1.27.1 (go run . in a module named demo, standard library only). With a 50 ms deadline, a 10 ms query returns rows, but a 200 ms query is abandoned when the context expires, returning context.DeadlineExceeded.
package main
import (
"context"
"errors"
"fmt"
"time"
)
func slowQuery(ctx context.Context, d time.Duration) (string, error) {
select {
case <-time.After(d):
return "rows", nil
case <-ctx.Done(): // cancelled or deadline exceeded
return "", ctx.Err()
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
res, err := slowQuery(ctx, 10*time.Millisecond)
fmt.Println("fast:", res, err)
res, err = slowQuery(ctx, 200*time.Millisecond)
fmt.Println("slow:", res, err, errors.Is(err, context.DeadlineExceeded))
}
Output:
fast: rows <nil> slow: context deadline exceeded true
Always defer cancel()
Calling the cancel function releases the context's resources even when the work finishes early.
Quick check: What does ctx.Done() return?
- A boolean
- An error value
- A channel that is closed when the context is cancelled or times out
- The remaining time
Answer
A channel that is closed when the context is cancelled or times out — Select on Done to stop work.