Go Lesson 39 – Context Package | Dataplexa

Context Package in Go

As Go applications grow larger and more concurrent, managing request lifecycles becomes critical. In this lesson, you will learn about Go’s context package and how it is used to control timeouts, cancellations, and shared values across goroutines.

The context package is heavily used in production systems such as APIs, microservices, and distributed applications.


What Is Context?

The context package provides a way to:

  • Cancel operations
  • Set deadlines and timeouts
  • Pass request-scoped values

Context allows different goroutines working on the same task to communicate when work should stop.


Why Context Is Important

Without context, long-running goroutines may:

  • Continue running after a request is cancelled
  • Waste CPU and memory
  • Cause resource leaks

Context ensures graceful termination of operations when they are no longer needed.


Importing the Context Package

import "context"

Creating a Base Context

Every context starts with a base context.

ctx := context.Background()

context.Background() is typically used in main functions, initialization, and top-level requests.


Context with Cancellation

You can create a cancellable context using context.WithCancel.

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Calling cancel() signals all goroutines using this context to stop.


Using Context in a Goroutine

Here is an example where a goroutine stops when the context is cancelled.

func worker(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            fmt.Println("Worker stopped:", ctx.Err())
            return
        default:
            fmt.Println("Worker running")
        }
    }
}

Context with Timeout

You can automatically cancel a context after a specific duration.

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

After 2 seconds, the context is cancelled automatically.


Complete Timeout Example

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancel()

    go func(ctx context.Context) {
        for {
            select {
            case <-ctx.Done():
                fmt.Println("Task cancelled:", ctx.Err())
                return
            default:
                fmt.Println("Processing...")
                time.Sleep(1 * time.Second)
            }
        }
    }(ctx)

    time.Sleep(5 * time.Second)
}

Context with Deadline

You can specify an exact time when the context should expire.

deadline := time.Now().Add(5 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()

Passing Values Using Context

Context can carry request-scoped values such as user IDs or request IDs.

ctx := context.WithValue(context.Background(), "userID", 101)

Retrieve values using:

userID := ctx.Value("userID")

Context values should be used sparingly and only for request-level data.


Real-World Use Case: HTTP Request Handling

In web servers, each HTTP request carries a context:

  • Client disconnects → context cancelled
  • Request timeout → context cancelled
  • Downstream services stop work

This prevents unnecessary database calls and API requests.


Best Practices

  • Always pass context as the first function parameter
  • Do not store contexts in structs
  • Do not use context for optional parameters
  • Always call cancel functions

Common Mistakes

  • Ignoring ctx.Done()
  • Forgetting to cancel contexts
  • Using context as a global variable

Practice Exercises

Exercise 1

Create a context with a 2-second timeout and stop a goroutine using it.

Exercise 2

Pass a request ID using context and print it inside a goroutine.


Key Takeaways

  • Context manages cancellation and timeouts
  • Essential for concurrent and distributed systems
  • Prevents resource leaks
  • Used extensively in production Go code

What’s Next?

In the next lesson, you will learn about Concurrency Patterns and how to design robust concurrent systems in Go.