Cancelling in-progress operations
You can manage in-progress operations by using Go
context.Context
. A Context
is a
standard Go data value that can report whether the overall operation it
represents has been cancelled and is no longer needed. By passing a
context.Context
across function calls and services in your application, those
can stop working early and return an error when their processing is no longer
needed. For more about Context
, see
Go Concurrency Patterns: Context.
For example, you might want to:
- End long-running operations, including database operations that are taking too long to complete.
- Propagate cancellation requests from elsewhere, such as when a client closes a connection.
Many APIs for Go developers include methods that take a Context
argument,
making it easier for you to use Context
throughout your application.
Cancelling database operations after a timeout
You can use a Context
to set a timeout or deadline after which an operation
will be cancelled. To derive a Context
with a timeout or deadline, call
context.WithTimeout
or
context.WithDeadline
.
Code in the following timeout example derives a Context
and passes it into
the sql.DB
QueryContext
method.
func QueryWithTimeout(ctx context.Context) {
// Create a Context with a timeout.
queryCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
// Pass the timeout Context with a query.
rows, err := db.QueryContext(queryCtx, "SELECT * FROM album")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// Handle returned rows.
}
When one context is derived from an outer context, as queryCtx
is derived
from ctx
in this example, if the outer context is cancelled, then the derived
context is automatically cancelled as well. For example, in HTTP servers, the
http.Request.Context
method returns a context associated with the request.
That context is cancelled if the HTTP client disconnects or cancels the HTTP
request (possible in HTTP/2). Passing an HTTP request’s context to
QueryWithTimeout
above would cause the database query to stop early either
if the overall HTTP request was cancelled or if the query took more than five
seconds.
Note: Always defer a call to the cancel
function that's returned when you
create a new Context
with a timeout or deadline. This releases resources held
by the new Context
when the containing function exits. It also cancels
queryCtx
, but by the time the function returns, nothing should be using
queryCtx
anymore.