Context in Go
A Basic walk-through …
Starting with what exactly is Context, Context is a type in Go which is included in context package. Context have timeout, cancellations, request-scoped values that is passed from one method to other including db server requests.
The incoming API requests should contain the parent context, that is then propagated to in-between methods before returning the response.
We can create derived(custom) context using the parent context with replacing the default values.When a context is cancelled all context derived from it are cancelled.
In GO, context plays important role while using go routines. same context can be used by multiple go-routines and also Context’s cancel() method may be called by go routines simultaneously. we’ll see about different methods in later part of blog.
Why we need separate type as Context(though we have struct type):
We should not use custom struct type for context to avoid the race conditions while replacing the local scoped values.
Let’s consider an example -
//pseudo codetype CustomCtxStruct struct {
timeout int
}
func New() *CustomCtxStruct {
return &CustomCtxStruct{timeout: 100}
}func (ctx *CustomCtxStruct) hop1() {ctx.timeout // A shared ctx.timeout is used for cancellation, deadlines, and metadata.
}func (c *CustomCtxStruct) hop2() {ctx.timeout // A shared ctx.timeout is used for cancellation, deadlines, and metadata.}go hop1()go hop2()
In above example, a shared value for timeout is passed as context to different methods hop1() and hop2(). If we try to replace the timeout value specific for each functionality here it can create race conditions.
In context.Context these cases are handled by Mutex, therefore using the Context type is more safe.
We should pass a Context explicitly to each function that needs it. The Context should be the first parameter,
func DoSomething(ctx context.Context, arg Arg) error {// … use ctx …}
Do not pass a nil Context, even if a function permits it. Pass context.TODO if you are unsure about which Context to use.
Features / methods used in context :
context.TODO : This is empty context, contains no value or timeline. When the method does not accept any context object but for current usage we need to have some context then we can initialize context object with this .
If you are working inside your own package and do not have any context available, in this case you should use the TODO context or if there is any doubt about which context you have to use, you can use the TODO context.
context.Background :This also returns empty context similar to context.TODO that is why it is never canceled . As per official documentations, It is typically used by the main function, initialization, and tests, and as the top-level Context for incoming requests.
you should not use this context in a package directly; it should be used in your main function. If you are building a server with the net/http package, the main context will be provided by the request.
context.WithValue() : This method is used to create the derived context with key and value.
The key values are of type interface, and only should be used to pass request-scoped values and not the function parameters.
func WithValue(parent Context, key, val interface{}) Context
context.WithTimeout() : This method is used to create the derived context with timeout value to tell a using function that it should cancel/stop its work after the timeout elapses. After the timeout expired it gives the error as — “context deadline exceeded”
context.WithDeadline() : This method is used to create the derived context with specific time which is the deadline for the context using function. As soon as time gets to deadline it gives the error as — “context deadline exceeded”.
context.WithCancel() - This method returns derived context with copy of Parent context with Done channel. We have to call the cancel() method explicitly in this after the func execution, unlike in context created by WithTimeout(), WithDeadline() methods, cancel() method is automatically called after reaches the condition.
Example —
Use cases of context and cancellation propagation:
Context allows you to pass the scope values to methods.
cancel context — suppose user initiated a request which includes multiple hops of processing or multiple go routines to perform the task. Meanwhile user cancels the request in this case we want to cancel the current processing as well as the child processing initiated for further hops .This cancelling the all processes to proceeding further is called as cancellation propagation. Here we can use the context with cancel.
For the scenarios when we want to cancel the request after a certain period of time.. i.e the cases where server is taking more time to respond and we want to timeout the request after certain interval in this case we can use context with timeout.
Cases where we want to cancel the context after a specific time( if we are creating derived context it checks the the deadline for parent and if deadline time has already passed then it stops execution) we should use context with deadline.
Difference between gin.context and context.context -
Context is the most important part of gin framework. It allows us to pass variables between middle-ware , manage the flow, validate the JSON of a request and render a JSON response for example.
gin.context is like wrapper of context , it implements all the methods of context like deadline,done, err, value and have its additional method implementations.
Copy() method of gin context package returns a copy of the current context that can be safely used outside the request’s scope.This has to be used when the context has to be passed to a go-routines.
Thank you for reading !!