Hone logo
Hone
Problems

Propagating Request-Scoped Data in Go with context.Context

In distributed systems and concurrent Go applications, it's often necessary to pass request-scoped data, such as request IDs, user authentication tokens, deadlines, or cancellation signals, across different function calls and goroutines. The context.Context type in Go is specifically designed for this purpose, providing a standardized way to carry deadlines, cancellation signals, and request-scoped values across API boundaries and between goroutines.

This challenge focuses on implementing and demonstrating proper context propagation in a multi-stage Go operation.

Problem Description

Your task is to implement a function that simulates a multi-stage process, where each stage might perform an operation that requires access to request-scoped data. This data should be passed using context.Context.

You will need to:

  1. Define a main function that initiates a request and creates a context.Context with some custom request-scoped values.
  2. Implement several hypothetical "stages" or "services" that perform distinct operations. Each of these stages must accept a context.Context as its first argument.
  3. Propagate the context.Context through all subsequent function calls within each stage, and if applicable, to other goroutines spawned within a stage.
  4. Demonstrate how to retrieve request-scoped values from the context within the stages.
  5. Showcase context cancellation: Implement a mechanism where the context can be cancelled, and how downstream operations gracefully handle this cancellation.

Key Requirements:

  • Use context.WithValue to associate custom data (e.g., a request ID, user ID) with the context.
  • Use context.WithCancel to allow for explicit cancellation of the context.
  • Each function that is part of the request processing chain must accept context.Context as its first parameter.
  • Demonstrate retrieving values using ctx.Value().
  • Handle potential errors returned by context operations (e.g., ctx.Done()).
  • When a context is cancelled, all goroutines or operations listening to that context should stop their work and return promptly.

Expected Behavior:

  • The main function should create a root context with some initial values and a cancellation function.
  • When values are added to the context, they should be retrievable in downstream functions.
  • When the context is cancelled (either explicitly or due to a deadline, though explicit cancellation is the focus here), all ongoing operations associated with that context should cease.
  • The program should output messages indicating the progress of each stage and whether it successfully completed or was cancelled.

Edge Cases to Consider:

  • What happens if ctx.Value() is called with a key that doesn't exist? (It should return nil).
  • How do you handle operations that might take a long time and need to respect the context's cancellation?

Examples

Example 1: Successful Operation without Cancellation

Input:
A root context is created with a request ID "req-123" and a user ID "user-abc".
The context is not cancelled.
The simulated stages execute successfully.

Output:
Starting request req-123 for user user-abc.
Stage 1: Processing...
Stage 1: Done.
Stage 2: Processing...
Stage 2: Done.
Stage 3: Processing...
Stage 3: Done.
Request req-123 completed successfully.

Example 2: Operation Cancelled Mid-way

Input:
A root context is created with a request ID "req-456" and a user ID "user-xyz".
The context is cancelled after Stage 1 completes.
Stage 2 is interrupted by the cancellation.

Output:
Starting request req-456 for user user-xyz.
Stage 1: Processing...
Stage 1: Done.
Cancelling request req-456.
Stage 2: Detected cancellation, stopping.
Stage 3: Skipped due to cancellation.
Request req-456 was cancelled.

Constraints

  • The solution must be written in Go.
  • Standard Go libraries, including context, fmt, time, and sync, are permitted.
  • The core logic should demonstrate the propagation of context.Context and its associated values/cancellation.
  • Focus on clarity and correctness of context usage rather than complex algorithmic solutions within the stages.

Notes

  • Think about how to define custom key types for context.WithValue to avoid collisions. An empty struct or a dedicated type is a common pattern.
  • Consider using select statements with ctx.Done() to gracefully exit goroutines or long-running operations when the context is cancelled.
  • The "stages" can be simple functions that print messages, simulate work with time.Sleep, and check for context cancellation.
  • The goal is to understand the mechanics of context propagation, not to build a production-ready distributed system component.
Loading editor...
go