# Context

The context package in Go provides a way to manage request-scoped data, deadlines, and cancellation signals across API boundaries and between processes.

It is a must if you want to build robust, production-ready applications in Go, particularly for handling concurrent workloads like HTTP servers, database queries, and background tasks.

Incoming requests to a server should create a Context, and outgoing calls to servers should accept a Context. The chain of function calls between them must propagate the Context, optionally replacing it with a derived Context created using `WithCancel`, `WithDeadline`, `WithTimeout`, or `WithValue`. When a Context is canceled, all Contexts derived from it are also canceled.

## Context

`context.Context`

The base interface that provides methods to retrieve deadlines, cancellation signals, and values.

* `Done() <-chan struct{}`: Returns a channel that closes when the context is canceled or times out.
* `Err() error`: Returns the reason for cancellation, if any.
* `Deadline() (time.Time, bool)`: Returns the deadline and whether a deadline is set.
* `Value(key any) any`: Retrieves request-scoped values.

## Functions in `context` Package

### context.WithCancel

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

Returns a copy of parent context that can be manually canceled by calling the returned cancel function.

### context.WithDeadline

```go
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
```

Returns a copy of parent context that automatically cancel after deadline exceeded.

### context.WithTimeout

```go
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
```

Returns a copy of parent context that automatically cancels after a specified duration. `WithTimeout` returns `WithDeadline(parent, time.Now().Add(timeout))`.

### context.WithValue

```go
func WithValue(parent Context, key, val any) Context
```

Returns a copy of parent context that carries request-scoped values.

## Best Practices

* **Pass Context Explicitly**:
  * Always pass `context.Context` as the first argument to functions handling operations that may require cancellation or deadlines.
  * Use context to propagate request metadata (e.g., trace IDs) across HTTP handlers or gRPC interceptors.
  * Combine contexts appropriately to propagate cancellations or deadlines.
* **Respect Cancellation**:
  * Periodically check ctx.Done() in long-running operations and exit promptly when canceled.

    ```go
    select {
    case <-ctx.Done():
        return ctx.Err()
    default:
        // Continue processing
    }
    ```
* **Use Timeouts Sparingly**:
  * Avoid overusing `context.WithTimeout` in nested operations to prevent conflicting deadlines. Set timeouts at higher levels and propagate them down.
* **Avoids**:
  * **Using context.WithValue for Critical Data**: Use `WithValue` only for request-scoped data. Avoid storing critical or large data; instead, pass such data explicitly.
  * **Using `context.Background` Everywhere**: Use `context.Background` only for root-level operations (e.g., in main or tests).
  * **Avoid Mutating Values in Context**: Contexts are immutable. Avoid attempts to modify or replace values in context.

## Example

```go
package main

import (
    "context"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
        defer cancel()

        err := doWork(ctx)
        if err != nil {
            http.Error(w, "Request timed out", http.StatusRequestTimeout)
            return
        }
        w.Write([]byte("Success"))
    })

    http.ListenAndServe(":8080", nil)
}

func doWork(ctx context.Context) error {
    select {
    case <-time.After(3 * time.Second): // Simulate long work
        return nil
    case <-ctx.Done():
        return ctx.Err()
    }
}
```

* In above example we try to simulate long work and it should response with error `Request timed out`.
* Try to make the timeout longer and see what the result is.

## Reference

* <https://pkg.go.dev/context>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bagus-cahyono.gitbook.io/programming-notes/golang/context.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
