$Id: 231

$SOId: 2743

Package context in standard library provides type Context which is hard to explain because it has multiple uses.

Here are the most common uses of context.Context:

Creating a context

In most cases you’ll be calling existing API that requires context.Context.

If you don’t have one, use context.TODO() or context.Background() functions to create it. Read about the difference.

context.Context is an immutable (read-only) value so you can’t modify it.

To create e.g. a context with value, you call context.WithValue() which returns a new context that wraps existing context and adds additional information.

context.Context is an interface so you could pass nil but it’s not recommended.

Many APIs expect non-nil value and will crash if passed nil so it’s best to always pass one created with context.Background() or context.TODO().

There is no performance issue because those functions return shared, global variables (yay immutability!).

Using context with timeout to set timeout for HTTP requests

Repeating an example from HTTP client article here’s a way to create a context with timeout to ensure HTTP GET request doesn’t hang forever:

// allow error, no playground
package main

import (
	"context"
	"log"
	"net/http"
	"time"
)

func main() {
	// :show start

	// httpbin.org is a service for testing HTTP client
	// this URL waits 3 seconds before returning a response
	uri := "<https://httpbin.org/delay/3>"
	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		log.Fatalf("http.NewRequest() failed with '%s'\\n", err)
	}

	// create a context indicating 100 ms timeout
	ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*100)
	// get a new request based on original request but with the context
	req = req.WithContext(ctx)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		// the request should timeout because we want to wait max 100 ms
		// but the server doesn't return response for 3 seconds
		log.Fatalf("http.DefaultClient.Do() failed with:\\n'%s'\\n", err)
	}
	defer resp.Body.Close()
	// :show end
}

HTTP client knows how to interpret context with a timeout. You just need to create and provide it.