Hone logo
Hone
Problems

Graceful Shutdown with context.WithCancel

Contexts in Go are fundamental for managing request-scoped values and cancellation signals. This challenge focuses on implementing a simplified version of context.WithCancel to understand how cancellation works under the hood. You'll create a function that returns a new context and a cancel function, allowing you to signal cancellation to any goroutines using the new context.

Problem Description

Your task is to implement a function WithCancel(parent context.Context) (context.Context, func()) that mimics the behavior of context.WithCancel. This function should:

  1. Create a new context: The function should create a new context derived from the parent context. This new context will inherit the values and deadlines from the parent.
  2. Return a cancel function: The function should return a function of type func(). This cancel function, when called, will signal cancellation to the new context.
  3. Cancellation Signal: When the cancel function is called, all goroutines that receive the new context should be notified of the cancellation. For simplicity, we'll represent this notification by printing a message from within a simulated worker goroutine. The worker goroutine should check the context's Done() channel periodically and exit gracefully when it receives a signal.
  4. No Leakage: The cancel function should only affect the context it created. Calling the cancel function on a different context should have no effect.

Expected Behavior:

  • When WithCancel is called, a new context and a cancel function are returned.
  • Goroutines using the new context should continue to execute until the cancel function is called.
  • When the cancel function is called, the Done() channel of the new context should be closed.
  • Goroutines using the new context should detect the closed Done() channel and exit gracefully.
  • Calling the cancel function multiple times should have the same effect as calling it once.
  • The parent context should remain unaffected by the cancellation of the child context.

Examples

Example 1:

Input: parent context is background context, worker goroutine receives the new context.
Output: Worker goroutine runs for a short time, then prints "Worker exiting" after cancel is called.
Explanation: The `WithCancel` function creates a new context and a cancel function. The worker goroutine receives the new context and periodically checks its `Done()` channel. When the cancel function is called, the `Done()` channel is closed, signaling cancellation to the worker goroutine, which then exits.

Example 2:

Input: parent context is background context, multiple worker goroutines receive the new context.
Output: All worker goroutines exit gracefully after cancel is called.
Explanation: The `WithCancel` function creates a new context and a cancel function. Multiple worker goroutines receive the new context and periodically check its `Done()` channel. When the cancel function is called, the `Done()` channel is closed, signaling cancellation to all worker goroutines, which then exit.

Example 3: (Edge Case)

Input: parent context has a deadline, worker goroutine receives the new context.
Output: Worker goroutine exits either due to the deadline or the cancel function being called, whichever happens first.
Explanation: The new context inherits the deadline from the parent context. If the deadline expires before the cancel function is called, the worker goroutine will exit due to the deadline. If the cancel function is called before the deadline expires, the worker goroutine will exit due to the cancellation signal.

Constraints

  • The WithCancel function must not leak any goroutines.
  • The cancel function must only affect the context it was created for.
  • The solution should be efficient and avoid unnecessary allocations.
  • The worker goroutines should check the context's Done() channel at least once every 10 milliseconds.

Notes

  • You can use the context package's background context as the parent context.
  • Consider using a channel to signal cancellation.
  • Think about how to ensure that the cancel function only affects the context it was created for.
  • The focus is on understanding the core mechanism of cancellation, not on implementing all the features of context.WithCancel. You don't need to handle timeouts or values.
  • You'll need to create a simple worker goroutine to test your implementation. This worker should periodically check the context's Done() channel and exit when it's closed.
Loading editor...
go