Sobes.tech
Junior

What is a context in Go?

sobes.tech AI

Answer from AI

The (context.Context) in Go is an object that carries deadlines, cancellation signals, and request-specific data. It is used to manage the lifecycle of goroutines and pass information between them during the execution of a single request/operation.

Main characteristics:

  • Thread-safe: Can be safely passed between goroutines.
  • Immutable: Once created, a Context cannot be changed. Derivative contexts are created based on the parent.
  • Hierarchical: Contexts form a tree with a root (context.Background() or context.TODO()). Cancelling a parent context cancels all its children.

Main functions of the context package:

  • context.Background(): An empty context, usually used in main functions, top-level requests, or testing. Never canceled.
  • context.TODO(): Also an empty context. Used as a placeholder when it is unknown which context to use, or if the context functionality is not yet implemented.
  • context.WithCancel(parent Context): Returns a new child context and a cancel function. Calling the cancel function cancels this context and all its children.
  • context.WithDeadline(parent Context, deadline time.Time): Returns a child context that automatically cancels when the specified time is reached. Also returns a cancel function for manual cancellation.
  • context.WithTimeout(parent Context, timeout time.Duration): Same as WithDeadline, but with a duration.
  • context.WithValue(parent Context, key, val interface{}): Returns a child context with an assigned value for the key.

Usage:

  • Operation cancellation: For example, timeout of an HTTP request or interruption of a long operation.
  • Data passing: For example, request ID for logging, authentication information.

Example of using context.WithTimeout:

package main

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

func longRunningOperation(ctx context.Context, resultChan chan string) {
	select {
	case <-time.After(3 * time.Second):
		// Operation completed successfully
		resultChan <- "Operation completed"
	case <-ctx.Done():
		// Context was canceled
		err := ctx.Err() // Get the reason for cancellation
		resultChan <- fmt.Sprintf("Operation cancelled: %v", err)
	}
}

func main() {
	// Create a context with a 2-second timeout
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel() // Ensure cancel is called

	resultChan := make(chan string, 1)

	go longRunningOperation(ctx, resultChan)

	// Wait for result or cancellation
	select {
	case res := <-resultChan:
		fmt.Println(res)
	case <-ctx.Done():
		fmt.Printf("Main context done: %v\n", ctx.Err())
	}

	// Wait a bit to let the goroutine finish if it was canceled
	time.Sleep(1 * time.Second)
}

In this example, longRunningOperation checks the context for cancellation. If the main context's timeout (2 seconds) expires before the operation (3 seconds) completes, the goroutine receives a cancellation signal via ctx.Done() and terminates.