In a Go application, there is a context that makes things more interesting. A context carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. When working with a request it can be used to cancel or timeout the request. A cancel can happen for many different reasons. The user could close their browser or click cancel as the request is being processed. There could be a bad internet connection or some other network issue. A client could timeout deciding the request is taking too long and close it. Regardless of the reason the context will signal it is done. This means work that has not yet been completed can be skipped.
Some packages for databases, http clients and others will require a context to be passed into them. The others will likely have a way to set it. I didn’t understand why initially. There was a context already set on the request so I just passed it along. When a context would get canceled we started seeing context-canceled errors. This is because these packages would act on that done context signal by stopping all their processing and returning an error.
ctx := request.Context()
// lookup a person from the database person, err := databaseCall(ctx)
…
// databaseCall Looks up a person from the database.
funcdatabaseCall(ctxcontext.Context) (Person, error) {
logInfo(ctx, "Making the database call")
var person Person
// pause for a bit to allow the context to be cancelled
err := pause(ctx)
if err != nil {
return person, err
}
// the popular pgxpostgres database package requires a context to be set in most operations
connection, err := pgx.Connect(ctx,
"postgres://postgres:postgres@localhost:5432/postgres")
if err != nil {
