ProgrammingBackend Go Developer

How does the built-in context package work in Go? What is it used for, how to properly create and cancel contexts? What mistakes are made when using it?

Pass interviews with Hintsage AI assistant

Answer

The context package is the standard for managing the lifecycle (cancellation, timeout) and passing metadata between parts of the code, especially when working with goroutines and external calls (HTTP, DB).

Creation:

  • context.Background() — root context
  • context.WithCancel(parent) — new context with cancellation
  • context.WithTimeout(parent, duration) — context with timeout
  • context.WithValue(parent, key, value) — context with data

It's important to cancel the context to properly free up resources. Example:

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() // ctx is then used in goroutine/HTTP request

The standard pattern is to pass the context as the first argument of functions, example:

func process(ctx context.Context) error { ... }

Trick Question

When can you pass context.TODO() and context.Background() instead of a real context, and what is the difference between them?

Many use context.Background() as a placeholder. However:

  • context.Background() is the root of the tree, use it only in main() and tests when initializing the "context tree" itself.
  • context.TODO() is needed when it's unclear what the context should be — for temporarily "plugging gaps" during refactoring. In production code, TODO is unacceptable: you need to know exactly what is being passed and where.

Examples of Real Errors Due to Ignorance of Subtleties


Story

In a microservice, they forgot to call cancel() after creating context.WithTimeout() — requests were stuck, finished goroutines left "hanging" timers in the runtime, leading to memory leaks.


Story

Passing context.Background() instead of the context from the request in handlers lost the entire cancellation chain and trace-id, causing timeout constraints not to work and request cancellations to fail.


Story

Through context.WithValue(), developers passed data, but the keys were strings. As a result, due to possible key collisions from different packages, unexpected errors occurred ("key already occupied"). Proper practice: use unique types for keys.