Go Context Management: Handling Request-Scoped Data and Cancellation
This challenge focuses on implementing and utilizing Go's context package, a crucial tool for managing request-scoped data, timeouts, and cancellations across API boundaries and between goroutines. You will build a system that simulates handling incoming requests, passing context through various stages, and reacting to cancellation signals.
Problem Description
You are tasked with creating a simplified service that processes incoming requests. Each request needs to carry a unique identifier and potentially some request-specific data. Crucially, the processing of a request might take a variable amount of time, and we need to be able to cancel it if it exceeds a certain duration or if an external signal is received.
Your goal is to:
- Create a context for each incoming request, including a unique request ID.
- Pass this context down through multiple stages of processing, simulating functions that might perform database lookups, external API calls, or other operations.
- Implement a timeout mechanism for the overall request processing.
- Demonstrate how to check for cancellation within the processing stages.
- Simulate an external cancellation signal that can interrupt a long-running request.
The expected behavior is that if a request times out or is externally cancelled, the processing should stop gracefully, and no further work should be done for that request.
Key Requirements
- Context Creation: For each simulated incoming request, create a
context.Contextthat carries a request ID. - Context Propagation: Pass the created context to all subsequent processing functions.
- Timeout: Implement a mechanism to cancel the context after a specified duration (e.g., 5 seconds).
- Cancellation Check: Within processing functions, periodically check if the context has been cancelled. If it has, stop processing and return an error.
- External Cancellation: Allow for a separate signal (e.g., an interrupt signal from the OS) to trigger context cancellation.
- Graceful Shutdown: Ensure that cancelled or timed-out requests do not continue to perform work.
Expected Behavior
- Requests that complete within the timeout and without external cancellation should report success.
- Requests that exceed the timeout should be cancelled, and the processing should stop.
- Requests that are cancelled by an external signal should stop processing immediately.
Edge Cases to Consider
- Requests that complete very quickly should not be affected by the timeout.
- Multiple requests should be handled concurrently without interfering with each other's contexts.
- Ensure proper error handling when cancellation occurs.
Examples
Example 1: Successful Request
Input: No external cancellation signal, request processing takes 2 seconds, timeout is 5 seconds.
Output:
Processing Request ID: req-123 - Stage 1 started
Processing Request ID: req-123 - Stage 1 completed
Processing Request ID: req-123 - Stage 2 started
Processing Request ID: req-123 - Stage 2 completed
Processing Request ID: req-123 - Request finished successfully
Explanation: The request completes within the 5-second timeout, and all stages of processing execute without interruption.
Example 2: Timeout Cancellation
Input: No external cancellation signal, request processing takes 7 seconds, timeout is 5 seconds.
Output:
Processing Request ID: req-456 - Stage 1 started
Processing Request ID: req-456 - Stage 1 completed
Processing Request ID: req-456 - Stage 2 started
(After 5 seconds)
Processing Request ID: req-456 - Request cancelled due to timeout.
Explanation: The request processing exceeds the 5-second timeout. The context.Done() channel will be closed after 5 seconds, signaling cancellation to the processing stages. Stage 2 (or any ongoing operation) should detect this and stop.
Example 3: External Cancellation
Input: An external OS interrupt signal (e.g., Ctrl+C) is received during request processing, request processing would take 10 seconds, timeout is 15 seconds.
Output:
Processing Request ID: req-789 - Stage 1 started
Processing Request ID: req-789 - Stage 1 completed
Processing Request ID: req-789 - Stage 2 started
(External interrupt signal received)
Processing Request ID: req-789 - Request cancelled by external signal.
Explanation: An external signal is caught and used to cancel the context for all active requests. The processing of req-789 should halt as soon as it detects the cancellation.
Constraints
- The maximum number of concurrent requests to simulate is 10.
- The request ID will be a string (e.g., "req-123").
- Processing stages should simulate work using
time.Sleep(). - The timeout duration for requests will be a fixed 5 seconds.
- The simulation should run for a maximum of 30 seconds before exiting gracefully.
Notes
- Consider using
context.WithTimeoutfor the timeout mechanism. - For external cancellation,
context.WithCancelcombined with listening to OS signals (os/signal) is a common pattern. - Within your processing functions, use a
selectstatement to checkctx.Done()and perform the actual work concurrently. This is key to non-blocking cancellation checks. - Think about how to pass request-specific data along with the context using
context.WithValue. - A good implementation will clearly show how the
context.Contextis passed and howctx.Done()is used to control the flow of execution.