WalzoneInterview Prep
📞 Interviewing soon? Practice with a realistic AI mock phone interview — it calls you, then scores you. First 15 min FREE →

Go · Expert · question 78 of 100

How can you use the ’context’ package in Go to control cancellation, timeouts, and propagate request-scoped values?

📕 Buy this interview preparation book: 100 Go questions & answers — PDF + EPUB for $5

The ‘context‘ package in Go is used to carry request-scoped values, cancellation signals, and deadlines across API boundaries and between various processes. It aims to improve code maintainability and reduce the risks associated with misusing timeouts, making it easier to manage the lifecycle of resources.

Let’s explore how to use ‘context‘ package in different situations.

1. Cancellation: You can use a context to cancel a long-running operation or multiple concurrent operations when the user decides to cancel the action.

Here is an example:

package main

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

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    go func() {
        time.Sleep(2 * time.Second)
        cancel() // Send the cancel signal after 2 seconds
    }()

    select {
    case <-ctx.Done():
        fmt.Println("Canceled:", ctx.Err())
    case <-time.After(5 * time.Second):
        fmt.Println("Timeout")
    }
}

In this example, a background context is created using ‘context.Background()‘, and a ‘cancel‘ function is derived from it using ‘context.WithCancel()‘. The program waits for either the cancel signal or a timeout. The context will be canceled after 2 seconds, printing "Canceled."

2. Timeouts: Using ‘context.WithTimeout()‘, you can set a deadline for an operation to complete, and it’ll automatically be canceled if it takes too long.

package main

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

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

    select {
    case <-ctx.Done():
        fmt.Println("Operation done:", ctx.Err())
    case <-time.After(5 * time.Second):
        fmt.Println("Timeout")
    }
}

In this example, a context with a 2-second timeout is created, meaning the operation will be canceled after 2 seconds. The result will be "Operation done: context deadline exceeded."

3. Propagate request-scoped values: Passing context values can be helpful for tracing or passing along metadata like request IDs.

package main

import (
    "context"
    "fmt"
)

type requestKey string

func main() {
    ctx := context.WithValue(context.Background(), requestKey("requestID"), "12345")

    requestID := ctx.Value(requestKey("requestID"))
    if requestID != nil {
        fmt.Println("RequestID:", requestID)
    } else {
        fmt.Println("No RequestID found")
    }
}

In this example, we create a new context and store the value ‘"12345"` using the ‘"requestID"` custom key type. Later, we can retrieve the value by using ‘ctx.Value()‘ method.

Remember that when using the ‘context‘ package, always pass context as the first parameter of a function, do not store it in structs, and avoid passing values that are request-shared via context (use proper function parameters for that purpose).

Reading is step one. Saying it out loud is the interview. Our AI interviewer calls your phone and runs a realistic Go interview — then scores it.
📞 Practice Go — free 15 min
📕 Buy this interview preparation book: 100 Go questions & answers — PDF + EPUB for $5

All 100 Go questions · All topics