What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Go’s context package lets a caller signal that downstream work should stop when a request is canceled or its deadline expires. Think of a waiter learning that a table has left: continuing to prepare that table’s order is wasted effort. In a Go program, the request context carries that signal to the functions and operations doing the work.

What does Go’s Context carry?

A context.Context carries a deadline, a cancellation signal, and request-scoped values across API boundaries, as Go team member Sameer Ajmani explains in Go Concurrency Patterns: Context. It does not perform cancellation by itself; it gives code a way to learn that work is no longer needed.

A context can be passed from a request handler to the functions it calls, and then to downstream operations. A context derived from a parent inherits cancellation: when the parent is canceled, its descendants are canceled too. A derived deadline is whichever comes first—the deadline set on the child or the deadline inherited from its parent.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How does cancellation stop work?

The context’s Done method returns a channel that closes when the context is canceled or its deadline expires. Work that can take time should observe that signal and return when it is no longer useful. Go’s guidance is that goroutines serving a canceled or timed-out request should exit promptly so the system can reclaim their resources.

Cancellation is cooperative, not a forceful interruption. Calling a CancelFunc does not kill arbitrary code or wait for it to finish. A function must check ctx.Done(), or call an API that accepts and observes the context, for cancellation to stop the work.

Observe cancellation in a long-running operation

A loop doing work directly can select on the context’s cancellation channel. The operation should return an appropriate error when the context ends rather than continuing indefinitely.

func process(ctx context.Context) error {
    for {
        select {
        case <-ctx.Done():
            return ctx.Err()
        default:
            // Do one unit of work.
        }
    }
}

This pattern only helps if each unit of work is bounded or otherwise able to yield control. If a function blocks inside a call that does not accept a context, the cancellation signal cannot interrupt that call.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do you cancel a database operation when a request ends?

Pass the incoming request context to a context-aware database method. If a client closes its connection and the request context is canceled, passing that context downstream allows the database operation to be canceled as well. Go’s database cancellation guide demonstrates deriving a timeout and using QueryContext:

func queryWithTimeout(ctx context.Context, db *sql.DB) error {
    queryCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    rows, err := db.QueryContext(queryCtx, "SELECT * FROM album")
    if err != nil {
        return err
    }
    defer rows.Close()

    // Process rows while the request remains useful.
    return nil
}

The five-second timeout is the Go documentation’s illustrative example, not a general recommendation. Choose a duration that fits the service’s requirements. Because the incoming context is the parent, its cancellation or earlier deadline still applies to the query.

Why defer the cancel function?

Call the CancelFunc returned by WithTimeout or WithDeadline, even if the operation completes before the deadline. Go’s documentation recommends defer cancel(); failing to call it can retain the derived context and its children until the parent is canceled. The context package documentation also notes that go vet checks for CancelFunc use on control-flow paths.

When should you derive a new context?

Use a derived context when a particular operation needs a tighter deadline or its own cancellation scope. Keep the request context as its parent so cancellation upstream still propagates. If no narrower deadline or independent cancellation is needed, pass the existing context through instead of creating extra contexts.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Parent request deadline: bounds work to the time allowed for the overall request.
  • Local timeout: gives a specific downstream call a shorter time budget while remaining subject to the parent’s cancellation and deadline.
  • Shared lifetime: work that must outlive an individual request needs a deliberately different lifecycle; do not accidentally attach it to a request that may end first.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How should functions receive a Context?

Pass a context explicitly to each function that needs it, generally as the first argument. Go’s guidance on contexts and structs advises against storing contexts in structs for ordinary per-call work. Context values are intended for request-scoped data that crosses API boundaries, not as a substitute for optional function parameters.

For each downstream call, check that the API actually accepts and observes a context. For database access, Go’s relational database guidance documents context-aware methods such as QueryContext. Passing a context to one layer does not automatically cancel work hidden in a lower-level call that ignores it.

Common cancellation mistakes

  • Creating a timeout but forgetting its cancel function: defer the cancel function as soon as the derived context is created.
  • Passing a context only partway: propagate it into downstream APIs that support cancellation, rather than dropping it before the expensive or blocking operation.
  • Assuming cancellation forcibly stops code: add cancellation checks to your own long-running work, and use context-aware APIs for blocking operations.
  • Putting a per-request context in a struct: pass it explicitly to methods or functions that need it, as recommended by the Go project.
  • Treating a sample timeout as a universal setting: choose the deadline based on the work and the service’s requirements.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.