Understanding it
The context
package is used in request scope to carry values and signals like cancel
and deadline
.
My main use is with HTTP request is made and I need a way to cancel all the entire process if the user cancels the request.
For instance, if you have this process in your server:
graph LR; req(Request)-->srv(Server); srv-->func(Function); func-->db(Database);
And the request is cancelled, you need to cancel all the subsequent executions.
To do that, we use the context
package.
func DoSomething(ctx context.Context, value string) {
select {
case <-ctx.Done():
// release
default:
// do something
}
}
Another interesting thing is third party libraries uses the context
to retrieve and use information inside it.
For instance, newrelic
grabs Transaction
information to compute a request time and trace it.
Using it
It is pretty simple.
Every function call that hash a request scope, it must have the 1st argument as ctx context.Context
.
func Save(ctx context.Context, name string) error {
tx, err := dbConn.Begin()
if err != nil {
// handle
return err
}
_, err := tx.ExecContext(ctx, 'INSERT INTO names(name) VALUES (?)', name)
if err != nil {
return err
}
return nil
}
func Service(ctx context.Context, name string) error {
return Save(ctx, name)
}
func Handler(w http.ResonseWriter, r *http.Request) {
name := r.URL.Query("name")
if err := Service(r.Context(), name); err != nil {
// handle error
return
}
w.Write([]byte(name))
return
}
So it works like this:
graph LR; A(Handler) --context--> B(Service); B --context--> C(Database);
When a request is cancelled, all the signal is passed down.
If the database save is executing and the HTTP request is cancelled, a signal is passed and the ExecContext
is stopped.
Cancellation
WithCancel
Returns a cancel
function to signal a cancellation.
ctx, cancel := context.WithCancel(context.Background())
cancel()
WithDeadline
Returns a cancel
function to signal a cancellation or cancel it automatically at certain time.Time
.
// Cancels after 5 seconds or when cancel is called
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
cancel()
WithTimeout
Returns a cancel
function to signal a cancellation or cancel it automatically after a time.Duration
.
// Cancels after 5 seconds or when cancel is called
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
cancel()
Context Values
Withvalue
Pass values through context:
ctx := context.Background()
ctx = context.WithValue(ctx, key, value)
Retrieve value
if value, ok := ctx.Value(key).(type); ok {
// handle
}