Golang Context (A Complete Guide)
Introduction
In Go, contexts are used to pass request-scoped values, deadlines, and cancellation signals between processes and API boundaries. Since contexts are immutable, it is safe to pass them around even between different goroutines.
Context is implemented in the standard library and you can find the docs here.
In this article, we are going to explore how to use context in real-world applications.
Creating Contexts
Contexts can be created in two ways:
- Using the
context.Background
function - Using the
context.TODO
function
The context.Background
function is used to create a context with no parent and is the root context. This context is used to create other contexts. The context.TODO
function is used to create a context with no parent and is used when the parent context is not yet available.
Passing Values with Context
One of the applications of context is to pass values between processes. This is done by using the context.WithValue
function. This function takes a context and a key-value pair and returns a new context with the key-value pair added to it.
To access the values in the context, we can use the context.Value
function. This function takes a context and a key and returns the value associated with the key.
Note: Passing values should only be done when necessary otherwise use arguments to pass values. Values in the context should be request-scoped and not application-scoped.
To avoid collisions, it is recommended to use a custom type as the key.
In the above program, we are passing a as a value in the context. We can also give primitive types like string
, int
, bool
, etc. as values in the context. In the main function, we are accessing the value using the context.Value
function and type asserting it to the User
struct.
Cancellation with Context
Cancellation is important in cases where we want to stop a process if it takes too long. For example, if we are requesting an API endpoint and the request takes too long, we can cancel the request and return an error. This will prevent the request from hanging indefinitely and misusing resources.
Contexts can also be used to cancel a process. This is done by using the context.WithCancel
function. This function takes a context and returns a new context and cancel function. The cancel function is then used to cancel the context.
A lot is going on in the above program. Let’s break it down.
In the someFunc
function, we are using the select
statement to check if the context has been canceled. If the context has been canceled, we print Context canceled
. If the context has not been canceled, we print Context not canceled
.
The ctx.Done
function returns a channel that is closed when the context is canceled. This is a method implemented on the context.Context
interface. The time.After
function returns a channel that sends the current time after the duration has elapsed. This is used to simulate a process that takes a long time.
In the main function, we are creating a context using the context.Background
function. We are then creating a new context using the context.WithCancel
function. This function takes a root context and returns a new context and a cancel function. The cancel function is used to cancel the context. We are then passing the new context to the someFunc
function.
The main function then sleeps for 2 seconds and then calls the cancel function. This cancels the context and the ctx.Done
channel is closed. This causes the select
statement in the someFunc
function to print Context canceled
.
The main function again sleeps for 2 seconds and then exits. This is to show that the time.After
channel does not send the current time after 5 seconds. This is because the context was canceled after 2 seconds.
The above program prints the following output:
Timeout with Context
Timeout is another important application of context. This is used to cancel a process if it takes too long. This is done by using the context.WithTimeout
function. This function takes a context and a duration and returns a new context and cancel function. The cancel function is then used to cancel the context.
The difference between context.WithCancel
and context.WithTimeout
is that the context.WithTimeout
function takes a duration as an argument. This is the duration after which the context is canceled. The context.WithCancel
function does not take a duration as an argument. This is because the cancel function can be called at any time to cancel the context.
The above program prints the following output:
Deadline with Context
Deadlines are similar to timeouts. The difference is that deadlines are absolute times. This is done by using the context.WithDeadline
function. This function takes a context and a time and returns a new context and cancel function. The cancel function is then used to cancel the context.
Absolute time is the time since the Unix epoch. This is the time since January 1, 1970 at 00:00:00 UTC.
The above program prints the following output:
Example: Context with HTTP Server
In this example, we are going to create a simple HTTP server that implements a context middleware function to handle any timeouts.
Create a new directory and initialize a new go program.
Open the program in your preferred editor.
Create a new directory out of the server folder.
Run the server program.
You could also test the server program using curl
.
Run the client program.
In the Server program, the middleware
function acts as a middleware function that adds context to the request. The context is canceled after 2 seconds. This is done by using the context.WithTimeout
function. The handler
function then checks if the context is canceled. If the context is canceled, the handler
function prints the error and returns a 500
status code. If the context is not canceled, the handler
function prints a message and returns a 200
status code.
The client program creates a context with a timeout of 1 second. This is done by using the context.WithTimeout
function. The context is then added to the request. The request is then sent to the server. The server then checks if the context is canceled. If the context is canceled, the server returns a 500
status code. If the context is not canceled, the server returns a 200
status code.
The above program prints the following output:
Conclusion
In this article, we discussed the context package and its components, including the context.Context
interface, the context.WithCancel
, context.WithTimeout
, and context.WithDeadline
functions, and how to use the context package to handle timeouts in HTTP servers.