Daksh Pareek

Welcome to my personal portfolio website, showcasing my projects and blogs.

Go Learning Journal 4: Context in Go

2025-03-17


These are raw learning notes from my journey with Go, documenting key concepts and examples for future reference. I reason with LLMs to understand some concepts better and sometimes copy paste the responses of that in my notes. These are not original thoughts.

Context in Go

Purpose of Context:

func logic(ctx context.Context, info string) (string, error)

Analogy: Food Delivery Service

Imagine you’re running a food delivery service:

  1. Order (Request)
  1. Delivery Person (Context) The delivery person carries:
// Without Context
func DeliverFood(trackingID string, deadline time.Time, instructions string) {
    // Manually pass everything
}

// With Context
func DeliverFood(ctx context.Context) {
    trackingID := ctx.Value("trackingID")
    // Deadline and cancellation built into context
    // All information travels together
}

Using context.WithValue:

Retrieving Values from Context:

Avoiding Key Collisions:


Context Cancellation in Go

Why Use Cancellation?

Imagine a web application that, upon receiving a request, launches several goroutines to perform tasks like fetching data from different services. If one of these tasks fails in a way that makes it impossible to fulfill the original request, there’s no point in continuing with the other tasks. Continuing would waste resources and possibly degrade the performance of your application.

By canceling the remaining tasks, you can:


Creating a Cancellable Context

To implement cancellation, you use context.WithCancel.

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

Example:

ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc() // Ensure that the context is canceled when we're done with it.

Detecting Cancellation

To check if a context has been canceled, use the Done() method:

doneChan := ctx.Done()

Example:

select {
case <-ctx.Done():
    // Context canceled, exit early.
    return
default:
    // Continue processing.
}


Server Resource Management

Servers are shared resources. Each client might try to consume as much of the server’s resources as possible without considering other clients. It’s the server’s responsibility to manage its resources to provide fair service to all clients.

Generally, a server can do four things to manage its load: • Limit simultaneous requests • Limit the number of queued requests waiting to run • Limit the amount of time a request can run • Limit the resources a request can use (such as memory or disk space)


Contexts with Deadlines and Timeouts

In Go, you can use the context package to create contexts that automatically cancel after a certain period (deadline) or duration (timeout).

Creating a Context with a Timeout

Use context.WithTimeout to create a context that cancels after a specific duration.

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

Creating a Context with a Deadline

Use context.WithDeadline to create a context that cancels at a specific time.

deadline := time.Now().Add(2 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel() // Ensure that the context is canceled to release resources

Child Contexts Cannot Outlive Parents: If the parent context is canceled or times out, the child context is also canceled, even if its timeout hasn’t expired yet.


Determining Why a Context Was Canceled

  1. Err() Method:

    • Returns nil if the context is still active.
    • Returns a non-nil error if the context has been canceled:
      • context.Canceled: If the context was manually canceled.
      • context.DeadlineExceeded: If the context timed out or reached its deadline.
  2. Cause() Function (since Go 1.20):

    • Use context.Cause(ctx) to get the error that caused the context to be canceled.
    • If you use context.WithCancelCause or context.WithTimeoutCause, you can pass a custom error upon cancellation.
    • If not, Cause() will return the same error as Err().

Handling Context Cancellation in Your Own Code

When Should You Handle Cancellation?