Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
func DoSomething(ctx context.Context, arg Arg) error {
// ... use ctx ...
}
package main
import (
"context"
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
ctx := context.Background()
for i := 0; i < 10; i++ { // Call process func 10 times
err := process(ctx)
if err != nil {
fmt.Println(err)
}
}
}
func process(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, 3*time.Second) // time out with 3 seconds
defer cancel()
// randomly decide the processing time
sec := rand.Intn(6)
fmt.Printf("wait %d sec: ", sec)
// pseudo process that takes <sec> seconds
done := make(chan error, 1)
go func(sec int) {
time.Sleep(time.Duration(sec) * time.Second)
done <- nil
}(sec)
// if context is done before receiving message from done channel, consider it as timeout.
select {
case <-done:
fmt.Println("complete")
return nil
case <-ctx.Done():
fmt.Println("timeout")
return ctx.Err()
}
}
main
- ctx is initialized with
Background
(empty context). - call
process
10 times.
- ctx is initialized with
process
- create a child context with
WithTimeout
(3 seconds to timeout)ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
- generate random int to decide how much the pseudo process takes to complete
sec := rand.Intn(6)
- make a
done
channel and runtime.Sleep
in the anonymous function with goroutine.done := make(chan error, 1) go func(sec int) { time.Sleep(time.Duration(sec) * time.Second) done <- nil }(sec)
- if done channel gets result before timeout, return
nil
otherwise returnctx.Err()
select { case <-done: fmt.Println("complete") return nil case <-ctx.Done(): fmt.Println("timeout") return ctx.Err() }
- create a child context with