Context Package

Back

Loading concept...

🎒 The Context Package: Your Backpack for Go Adventures

The Magic Backpack Story

Imagine you’re going on a treasure hunt with your friends. Before you leave, your mom gives you a special backpack with important things inside:

  • ⏰ A timer that tells you when to come home for dinner
  • 📝 A note with the secret password
  • 🚨 A walkie-talkie to call you back if needed

This backpack is Go’s Context Package! It carries important information and signals between different parts of your program—like passing notes between friends during a treasure hunt.


🎯 What You’ll Learn

graph TD A["Context Package"] --> B["Overview"] A --> C["Creation Functions"] A --> D["Cancellation"] A --> E["Values"] B --> B1["What is Context?"] C --> C1["Background & TODO"] C --> C2["WithCancel"] C --> C3["WithDeadline"] C --> C4["WithTimeout"] D --> D1["How Cancellation Works"] D --> D2["Done Channel"] E --> E1["WithValue"] E --> E2["Getting Values"]

📦 Context Package Overview

What is Context?

Think of context as a messenger bag that travels with your code. When you call a function, you hand it the bag. That function can:

  1. Look inside for important info
  2. Check if it’s time to stop working
  3. Pass the bag to other functions it calls

Real Example:

import "context"

func main() {
    // Create a basic backpack
    ctx := context.Background()

    // Now pass it to functions
    doWork(ctx)
}

func doWork(ctx context.Context) {
    // I have the backpack now!
    // I can check for signals
}

Why Do We Need Context?

Imagine you ask your friend to find a toy. But then:

  • 🍕 Pizza arrives and you don’t need the toy anymore
  • ⏰ It’s taking too long
  • 🏠 You need to go home

You need a way to tell your friend: “Stop looking! Come back!”

That’s exactly what context does for your Go programs.


🔧 Context Creation Functions

1. Background() - The Empty Backpack

This is your starting point. Like an empty backpack before you pack anything.

ctx := context.Background()

When to use:

  • Main function
  • Starting point of your app
  • When you don’t have a context yet

2. TODO() - The “Figure It Out Later” Backpack

When you’re not sure what context to use yet.

ctx := context.TODO()

When to use:

  • You’re still building your code
  • You’ll add proper context later

💡 Tip: TODO() is like a sticky note saying “fix this later”

3. WithCancel() - The Backpack with a Stop Button

This creates a backpack with a red button. Press it, and everyone with that backpack knows to stop!

// Create backpack with stop button
ctx, cancel := context.WithCancel(
    context.Background(),
)

// Give backpack to worker
go doWork(ctx)

// Later: Press the stop button!
cancel()
graph TD A["Parent Context"] -->|WithCancel| B["Child Context"] B --> C["cancel function"] C -->|When called| D["Child gets signal to STOP"]

4. WithDeadline() - The Backpack with an Alarm Clock

Set a specific time when work must stop.

// Stop at exactly 3:00 PM
deadline := time.Date(
    2024, 1, 1, 15, 0, 0, 0,
    time.Local,
)

ctx, cancel := context.WithDeadline(
    context.Background(),
    deadline,
)
defer cancel() // Always clean up!

Real Life: Like saying “Be home by 6 PM sharp!”

5. WithTimeout() - The Backpack with a Countdown Timer

Set how long until work must stop.

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

// Do work that must finish in 5 sec
result := fetchData(ctx)

Real Life: Like a game timer—you have 5 minutes to finish!

graph LR A["Start"] -->|5 seconds| B["Timeout!"] A --> C["Working..."] C --> D{Done before timeout?} D -->|Yes| E["Success!"] D -->|No| B

🚨 Context Cancellation

The Done() Channel - Your Walkie-Talkie

Every context has a Done() channel. It’s like a walkie-talkie that beeps when it’s time to stop.

func doWork(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            // Walkie-talkie beeped!
            // Time to stop
            fmt.Println("Stopping work!")
            return
        default:
            // Keep working
            fmt.Println("Still working...")
            time.Sleep(1 * time.Second)
        }
    }
}

Why Cancellation Matters

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

    go doWork(ctx)

    // Wait for timeout
    time.Sleep(5 * time.Second)
}

Output:

Still working...
Still working...
Still working...
Stopping work!    ← After 3 seconds

The Err() Method - What Happened?

After context is done, check why it stopped:

err := ctx.Err()

if err == context.Canceled {
    // Someone pressed cancel button
    fmt.Println("Work was canceled")
}

if err == context.DeadlineExceeded {
    // Timer ran out
    fmt.Println("Ran out of time!")
}

🏷️ Context Values

WithValue() - Putting Notes in the Backpack

Sometimes you need to pass extra information through your code. Like putting a secret note in the backpack.

// Put a note in the backpack
type userKey string

ctx := context.WithValue(
    context.Background(),
    userKey("userID"),
    "user-123",
)

// Pass backpack to functions
processRequest(ctx)

Getting Values Back

func processRequest(ctx context.Context) {
    // Look for the note
    userID := ctx.Value(userKey("userID"))

    if userID != nil {
        fmt.Println("User:", userID)
    }
}

⚠️ Important Rules for Values

graph TD A["Context Values"] --> B["DO ✅"] A --> C[DON'T ❌] B --> B1["Request-scoped data"] B --> B2["User IDs, trace IDs"] B --> B3["Authentication tokens"] C --> C1["Function parameters"] C --> C2["Optional settings"] C --> C3["Large data objects"]

Good Example:

// Request ID for logging
ctx = context.WithValue(
    ctx,
    requestIDKey,
    "req-abc-123",
)

Bad Example:

// DON'T DO THIS!
// Use function parameters instead
ctx = context.WithValue(
    ctx,
    "config",
    entireConfigObject,
)

🎮 Putting It All Together

Here’s a complete example showing everything:

package main

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

type requestID string

func main() {
    // 1. Create context with timeout
    ctx, cancel := context.WithTimeout(
        context.Background(),
        5*time.Second,
    )
    defer cancel()

    // 2. Add a value
    ctx = context.WithValue(
        ctx,
        requestID("reqID"),
        "REQ-001",
    )

    // 3. Start work
    go worker(ctx)

    // 4. Wait a bit, then cancel
    time.Sleep(2 * time.Second)
    cancel()

    time.Sleep(1 * time.Second)
}

func worker(ctx context.Context) {
    // Get the request ID
    reqID := ctx.Value(requestID("reqID"))
    fmt.Printf("[%s] Starting\n", reqID)

    for i := 1; ; i++ {
        select {
        case <-ctx.Done():
            fmt.Printf("[%s] Stopped: %v\n",
                reqID, ctx.Err())
            return
        default:
            fmt.Printf("[%s] Working %d\n",
                reqID, i)
            time.Sleep(500 * time.Millisecond)
        }
    }
}

Output:

[REQ-001] Starting
[REQ-001] Working 1
[REQ-001] Working 2
[REQ-001] Working 3
[REQ-001] Working 4
[REQ-001] Stopped: context canceled

🌟 Key Takeaways

Function What It Does Real-Life Example
Background() Empty starting context Empty backpack
TODO() Placeholder context “Fix later” note
WithCancel() Can be manually stopped Stop button
WithDeadline() Stops at exact time “Home by 6 PM”
WithTimeout() Stops after duration Game timer
WithValue() Carries data Secret note

🎯 Remember This!

Context is like a backpack 🎒

  • You pack it at the start
  • Pass it to every function
  • Everyone can check if it’s time to stop
  • It can carry small notes (values)
  • When canceled, everyone knows to stop

The Golden Rule: Always pass context as the first parameter of functions that need it!

func doSomething(ctx context.Context, ...) {
    // ctx is ALWAYS first!
}

Now you’re ready to use Go’s Context Package like a pro! 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.