Context in Go is a type that carries a request-scoped value across API boundaries. It is designed to be used in long-lived requests, such as an HTTP server handling multiple requests over the lifetime of a process.

One of the primary use cases of context is to cancel long-running operations. For example, if an HTTP server receives a request with a cancelation token, it can use that token to cancel the request if the client closes the connection. This helps to avoid resource leaks by freeing up resources that would have been used by the request.

Context can also be used to store request-scoped values, such as a database connection or an authenticated user. This allows different parts of the codebase to share information about the request without relying on global state or passing the values through function parameters.

To use context in Go, you first need to import the “context” package. Then, you can create a context by calling the context.WithValue function, which takes a parent context and a key-value pair. You can then pass the context to functions that accept it as an argument.

For example, here’s how you might create a context with a cancelation token and pass it to an HTTP handler:

package main

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

func handler(w http.ResponseWriter, r *http.Request) {
	ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
	defer cancel()

	// Do some work with the request.
	// If the client closes the connection,
	// the cancel function is called and the work is stopped.
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

In this example, the context is created with a timeout of one minute. If the client closes the connection before the handler finishes, the cancel function is called and the work is stopped.

It’s important to note that context is not intended to be used as a means of communication between goroutines. While it is possible to use context to pass values between goroutines, it is generally better to use channels for this purpose.

The context package also provides several functions for creating and manipulating contexts. These include:

  • context.Background: Returns a background context. This is the root of the context tree and is typically used as the parent of a context created with context.WithValue.
  • context.WithValue: Returns a new context with the given key-value pair. The new context is derived from the parent context and carries the value across API boundaries.
  • context.WithCancel: Returns a new context and a cancel function. The cancel function can be called to cancel the context and all contexts derived from it.
  • context.WithTimeout: Returns a new context and a cancel function. The cancel function is called when the timeout elapses or when the parent context is canceled, whichever occurs first.
  • context.WithDeadline: Returns a new context and a cancel function. The cancel function is called when the deadline elapses or when the parent context is canceled, whichever occurs first. Here’s an example of how you might use these functions to create a context with a cancelation token and a request-scoped value:
package main

import (
	"context"
	"fmt"
	"time"
)

func main() {
	// Create a background context with a cancelation token.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Create a new context with a request-scoped value.
	valueCtx := context.WithValue(ctx, "user_id", 123)

	// Create a new context with a deadline.
	deadline, _ := time.Parse(time.RFC3339, "2022-01-01T00:00:00Z")
	deadlineCtx, _ := context.WithDeadline(valueCtx, deadline)

	// Print the values from all three contexts.
	fmt.Println("Background:", ctx.Value("user_id"))
	fmt.Println("Value:", valueCtx.Value("user_id"))
	fmt.Println("Deadline:", deadlineCtx.Value("user_id"))
}

In this example, we create a background context with a cancelation token and a request-scoped value using the context.WithCancel and context.WithValue functions. We then create a new context with a deadline using the context.WithDeadline function.

When we print the values from the contexts, we can see that the values are propagated down the context tree. The background context has the cancelation token, the value context has both the cancelation token and the request-scoped value, and the deadline context has all three.

It’s worth noting that the context package is designed to be used with long-lived requests, such as an HTTP server handling multiple requests over the lifetime of a process. It is not intended to be used as a means of communication between goroutines or as a general-purpose synchronization mechanism.

In conclusion, the context package in Go is a powerful tool for carrying request-scoped values and cancelation tokens across API boundaries. It allows you to cancel long-running operations, store request-scoped values, and share information between parts of the codebase without relying on global state. If you’re building an application in Go, chances are you’ll find context to be an indispensable tool in your toolkit.