Context

Context carries deadlines, cancellation signals, and other request-scoped values across API boundaries and goroutines.

Why

  • Timeout
  • Deadline
  • Channel
  • Share data

Scenarios

  • Web request
    • HTTP request
    • gRPC

How to use

Create a context

ctx, cancel := context.Background()
ctx, cancel := context.TODO() // less common

Use withValue to share data

Imagine a map inside context.
package main

import (
    "context"
    "fmt"
)

func main() {
    ctx := context.Background()
    ctx = addValue(ctx)
    readValue(ctx)
}

func addValue(ctx context.Context) context.Context {
    return context.WithValue(ctx, "key", "test-value")
}

func readValue(ctx context.Context) {
    val := ctx.Value("key")
    fmt.Println(val) // test-value
}
From https://dev.to/gopher/getting-started-with-go-context-l7g

Use cancellation to terminate all process in the same pipeline

Ex: A client close their browser, then we should stop querying data from the database.
If cancellation is triggered, we receive messages from ctx.Done(). operation1 failed after 100 ms, and then operation2 is halted.
func operation1(ctx context.Context) error {
	// Let's assume that this operation failed for some reason
	// We use time.Sleep to simulate a resource intensive operation
	time.Sleep(100 * time.Millisecond)
	return errors.New("failed")
}

func operation2(ctx context.Context) {
	// We use a similar pattern to the HTTP server
	// that we saw in the earlier example
	select {
	case <-time.After(500 * time.Millisecond):
		fmt.Println("done")
	case <-ctx.Done():
		fmt.Println("halted operation2")
	}
}

func main() {
	// Create a new context
	ctx := context.Background()
	// Create a new context, with its cancellation function
	// from the original context
	ctx, cancel := context.WithCancel(ctx)

	// Run two operations: one in a different go routine
	go func() {
		err := operation1(ctx)
		// If this operation returns an error
		// cancel all operations using this context
		if err != nil {
			cancel()
		}
	}()

	// Run operation2 with the same context we use for operation1
	operation2(ctx)
}
From https://www.sohamkamani.com/golang/context-cancellation-and-values/

Use timeout and deadline so that app does not wait forever

// The context will be cancelled after 3 seconds
// If it needs to be cancelled earlier, the `cancel` function can
// be used, like before
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)

// Setting a context deadline is similar to setting a timeout, except
// you specify a time when you want the context to cancel, rather than a duration.
// Here, the context will be cancelled on 2009-11-10 23:00:00
ctx, cancel := context.WithDeadline(ctx, time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC))
From https://www.sohamkamani.com/golang/context-cancellation-and-values/

Reference