Go (Golang), What is Context?
Intro
As a go newcomer one thing that always tripped me up was context, what is it? What is it for? What is the difference between Context.TODO() and Context.Background()? These are all questions that I had, so I am writing this here to help both the reader and more importantly, myself
What is Context?
Let's start from the beginning, the context package was included in the release of Go 1.17 (August 2016). Its inclusion in the standard library was driven by the need for a unified and standardized approach to handling request-scoped values, cancellations, signals, and deadlines across concurrent processes. Its primary purpose os to address two key issues:
Passing Request-scoped Values
The
contextpackage can carry request-scoped values. This is useful for passing values such as API keys, user information, or trace IDs through a chain of function calls, where each function might be operating in a different goroutine.Here is an example of a use case that I had:
func (app *application) addAuthenticated(r *http.Request) bool { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := context.WithValue(r.Context(), isAuthenticatedContextKey, true) r = r.WithContext(ctx) next.ServeHTTP(w, r) } } func (app *application) isAuthenticated(r *http.Request) bool { isAuthenticated, ok := r.Context().Value(isAuthenticatedContextKey).(bool) if !ok { return false } return isAuthenticated }In this example, we are using setting the request context a value (key-value pairs) and in the next function checking if the key set is present.
Cancellation of Processes
allows you to cancel goroutines in a way that's both safe and consistent. This is useful in situations where you have long-running operations (network or database call) that you might want to abort if certain conditions are met (e.g., a deadline has passed, or the user cancels the operation).
As always, an example of a use case:
func (u *UserModel) Insert(user *User) error { query := ` INSERT INTO users (name, email) VALUES ($1, $2, $3, $4) RETURNING id, created_at, version` args := []any{user.name, user.email} // Use the context.WithTimeout() function to create a context.Context which carries a // 3-second timeout deadline. //NOTE: The timeout countdown begins from the moment that the context is created ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) // Importantly, use defer to make sure that we cancel the context before the Get() // method returns. defer cancel() //Pass in ctx as this will return after 3ish seconds if query is still in progress return m.DB.QueryRowContext(ctx, query, args...).Scan(&user.name, &user.email) }
What are the context types?
context.Background()Purpose: It's the root context which is typically used at the highest level of the application. It is never canceled, has no values, and no deadline. It's intended to be used as the initial context that flows through the application.
Usage: Ideal for main functions, initialization, and tests, or when no other context is available.
context.TODO()Purpose: This context is used as a placeholder. It indicates that the function has yet to be extended to support contexts, but it is planned to be implemented in the future. Like
context.Background(), it is never canceled, has no values, and no deadline.Usage: Useful when you're unsure about which context to use or when the current function will support context in the future.
context.WithCancel(parent Context)Purpose: Creates a new context derived from a parent context that can be canceled manually. When the cancel function returned by
WithCancelis called, the context is canceled.Usage: Suitable for creating a context that might need to be canceled before its operation completes, like in case of timeouts or incoming request cancellations.
context.WithDeadline(parent Context, deadline Time)Purpose: It's similar to
WithCancel, but it also sets a specific time at which the context will automatically be canceled.Usage: Useful for setting a deadline for a request or operation to complete. After the deadline, the context is canceled.
context.WithTimeout(parent Context, timeout Duration)Purpose: A convenience wrapper around
WithDeadline. Instead of specifying the exact time for cancellation, you specify a duration after which the context should be canceled.Usage: Ideal for operations that should be limited in execution duration, such as handling HTTP requests or database operations where you want to control the maximum time they can take.
Summary
And that is a wrap! Hope you enjoyed reading and learned a little more about the context package! As always to go in-depth check out the always great go documentation here: https://pkg.go.dev/context

