Exploring Context Package in Go: A Comprehensive Guide
Listen to what you know instead of what you fear.
— Richard Bach
Medium Link: Context Package You Should Know in Golang | by Wesley Wei | Jun, 2024 | Programmer’s Career
Hello, here is Wesley, Today’s article is about golang-context in Go. Without further ado, let’s get started.💪
1.1 Context Introduction
From the versions of the context package on context package versions - context - Go Packages, we can see that Go’s standard library introduced the context package in version go1.7beta1. It defines the Context type, which represents the context of a goroutine, can be used to transmit contextual information, such as cancellation signals, timeouts, deadlines, and key-value pairs.
We can understand it as a container for the context in which a program runs. Of course, this is just some basic understanding, and the Go documentation has a more critical statement:
The same Context may be passed to functions running in different goroutines; Contexts are safe for simultaneous use by multiple goroutines.
This statement suggests a close relationship between context and goroutines. Let’s continue to explore further.
1.2 Why Context
As we all know, a seemingly simple business request in the server-side is actually very complex. Multiple goroutines are working simultaneously to complete it. Some go to Redis to retrieve metadata, some go to S3 to retrieve specific data, and some go to call the interfaces of downstream microservices.
This requires that requests have a hierarchical relationship, making it easy to perform timeouts and resource recovery, for example, we do not want the downstream goroutines to continue executing tasks when the upstream request stops, as this will waste resources, resource leakage, or even service avalanche.
In Go’s unique design, context is introduced to solve this kind of problem (which is rarely seen in other programming languages).

Through context and goroutines’ cooperation, we can achieve the effect introduced in Go Concurrency Patterns: Context - The Go Programming Language in the introduction.
When a request is canceled or times out, all the goroutines working on that request should exit quickly so the system can reclaim any resources they are using.
As for how to implement it, we can find the answer in the source code analysis.
1.3 Creating and Using Context
We can create a context using the functions provided by the context package:
1. context.Background() and context.TODO()
context.Background() returns an empty context that does not contain any data, does not support cancellation operations, and does not have a deadline set. We typically use context.Background() in the main function, initialization, and testing code.
On the other hand, context.TODO() returns an empty context as well, but in terms of semantics, we choose to use context.TODO() when we are unsure which context to use.
1 | ctx := context.Background() |
WithCancel Example:
1 | package main |
WithDeadline, WithTimeout, WithValue, etc. Can be used as shown in the official examples Context Examples.
1.4 Context Source Code Analysis
The focus here is to analyze the example of
WithCancelin go1.22.4, specifically in the WithCancel function.
1 | func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { |
We can break down the execution steps as follows:
- Create a
cancelCtxobject, which serves as the childcontext - Then call
propagateCancelto establish the relationship between the parent and childcontexts. This way, when the parentcontextis canceled, the childcontextwill also be canceled. - Return the child
contextobject and the cancel function for the sub-tree.
cancelCtx and propagateCancel()
1 | type cancelCtx struct { |
The following function has three different cases related to the parent context:
- When
parent.Done() == nil, or in other words,parentwill not trigger the cancel event, the current function will simply return; - When the child context’s inheritance chain contains a cancellable context, it will check if
parenthas already triggered the cancel signal;- If already canceled, the child will be immediately canceled;
- If not canceled, the child will be added to
parent‘schildrenlist, waiting forparentto release the cancel signal;
- When the parent context is a developer-defined type, implements the
context.Contextinterface, and returns a non-empty channel in theDone()method;- Run a new Goroutine simultaneously monitoring
parent.Done()andchild.Done()Channels; - In
parent.Done()close, callchild.cancelto cancel the child context;
- Run a new Goroutine simultaneously monitoring
The purpose of context.propagateCancel is to synchronize cancel and end signals between parent and child, ensuring that when parent is canceled, the child also receives the corresponding signal, avoiding inconsistent states.
cancel()
The most important method is context.cancelCtx.cancel, which closes the Channel in the context and synchronizes the cancel signal to all child contexts:
1 | func (c *cancelCtx) cancel(removeFromParent bool, err, cause error) { |
From the source code, we can see that the cancel method can be called multiple times and is idempotent. In summary, we can create a simple diagram to illustrate the cancel process:

Other Methods
context.WithDeadline and context.WithTimeout have similar logic but also handle timers. They create a context.timerCtx during the creation process and check the deadline date of the parent context against the current date. They then create a timer using time.AfterFunc, and when the time exceeds the deadline, they call context.timerCtx.cancel to synchronize the cancel signal.
XXXCause further extends the error-related process, solving some annoying problems such as unfriendly error returns, inability to customize errors, and difficulty debugging when encountering issues that are hard to trace.
1 | ctx, cancel := context.WithCancelCause(parent) |
For more details, refer to the following article: Context cancel cause in Go 1.20. Go 1.20 introduced two new functions in… | by Peter Gillich | Dev Genius
1.5 Best Practices for context
Here are some best practices to consider:
- Do not store context in structs: Context was designed to facilitate passing between functions, not to store state information. Therefore, it’s best to maintain its fluidity rather than storing it in structs.
- Use context’s Value method sparingly: Although the Value method of context is very useful in some scenarios, overuse of this feature can make the code harder to maintain, especially when context is heavily used.
- Follow the lifecycle management rules of the context package: Generally, context should be created by the outermost function that initiates the request and passed down through the call chain. If your function needs to run in a subprocess and may need to be canceled or timed out, consider receiving a context parameter. Avoid storing and using context in global variables.
- Call cancel functions using defer statements: When using the
WithCancel,WithTimeout, orWithDeadlinefunctions to return cancel functions, you should call them to release related resources. The best practice is to call these cancel functions through defer statements before your function returns. - Create new contexts as much as possible: Instead of reusing existing contexts, this allows each request to have a context with a clear lifecycle.
1.6 Summary
The Go official recommendation is to use Context as the first parameter of functions. If we want to control the cancellation actions of all coroutines, almost all functions should have a Context parameter, and context will spread like a virus everywhere.
Additionally, functions like WithCancel actually create a series of linked list nodes. We know that operations on linked lists usually have O(n) complexity, and the more child nodes there are, the lower the efficiency will be.
So, what problem does the context package solve? The answer is: cancelation. It helps us better manage parallel control and better manage goroutine overuse. Although it is not perfect, it does solve the problem in a simple way.
More Series Articles about You Should Know In Golang:
https://wesley-wei.medium.com/list/you-should-know-in-golang-e9491363cd9a
And I’m Wesley, delighted to share knowledge from the world of programming. don’t forget to follow me, it would be a great help to me. See you in the next article. 👋
中文文章: https://programmerscareer.com/zh-cn/golang-context/
Author: Wesley Wei – Twitter Wesley Wei – Medium
Note: Originally written at https://programmerscareer.com/golang-context/ at 2024-06-13 01:12. If you choose to repost or use this article, please cite the original source.
Comments