Hone logo
Hone
Problems

Contextualized Task Execution in Go

Contexts in Go are a powerful tool for managing request-scoped values, cancellation signals, and deadlines across API boundaries and goroutines. This challenge asks you to build a simple task execution system that leverages Go's context package to gracefully handle task cancellation and timeouts. Understanding context usage is crucial for building robust and scalable Go applications.

Problem Description

You are tasked with creating a TaskExecutor that manages the execution of tasks within a given context. The TaskExecutor should accept a slice of functions (tasks), each of which takes a context.Context and returns a boolean indicating success or failure. The executor should run these tasks concurrently, respecting the context's cancellation signal and deadline.

The executor must:

  1. Accept a slice of tasks: Each task is a function of type func(context.Context) bool.
  2. Execute tasks concurrently: Launch each task in its own goroutine.
  3. Respect the context: Pass the provided context to each task. If the context is cancelled or the deadline is reached, the executor should stop accepting new tasks and attempt to gracefully shut down the running tasks.
  4. Return a slice of booleans: The returned slice should indicate the success (true) or failure (false) of each corresponding task.
  5. Handle errors gracefully: If a task panics, catch the panic and record the failure in the result slice.

Examples

Example 1:

Input: []func(context.Context) bool{
    func(ctx context.Context) bool {
        select {
        case <-time.After(2 * time.Second):
            fmt.Println("Task 1 completed")
            return true
        case <-ctx.Done():
            fmt.Println("Task 1 cancelled")
            return false
        }
    },
    func(ctx context.Context) bool {
        select {
        case <-time.After(1 * time.Second):
            fmt.Println("Task 2 completed")
            return true
        case <-ctx.Done():
            fmt.Println("Task 2 cancelled")
            return false
        }
    },
} , context.Background()
Output: [true false]
Explanation: Task 1 takes 2 seconds, Task 2 takes 1 second. The context is not cancelled, so both tasks complete successfully.

Example 2:

Input: []func(context.Context) bool{
    func(ctx context.Context) bool {
        select {
        case <-time.After(3 * time.Second):
            fmt.Println("Task 1 completed")
            return true
        case <-ctx.Done():
            fmt.Println("Task 1 cancelled")
            return false
        }
    },
    func(ctx context.Context) bool {
        panic("Task 2 panicked!")
        return true
    },
} , context.WithTimeout(context.Background(), 1 * time.Second)
Output: [false false]
Explanation: The context times out after 1 second. Task 1 is cancelled. Task 2 panics, which is caught and recorded as a failure.

Example 3: (Edge Case - Empty Task List)

Input: []func(context.Context) bool{}, context.Background()
Output: []bool{}
Explanation: If the task list is empty, return an empty slice.

Constraints

  • The number of tasks can range from 0 to 100.
  • Each task function should complete within 5 seconds even without context cancellation.
  • The TaskExecutor should return within 10 seconds, even if some tasks are long-running and the context is cancelled.
  • The input task functions cannot return errors. They should panic on any unexpected error condition.

Notes

  • Consider using a sync.WaitGroup to manage the goroutines.
  • The context.Done() channel is your primary tool for detecting cancellation.
  • Use recover() to handle panics within the tasks.
  • Focus on clean, readable code that demonstrates a good understanding of Go's concurrency primitives and the context package.
  • The time package is available for simulating task durations. You'll need to import it.
  • The fmt package is available for printing debug messages. You'll need to import it.
  • The sync package is available for synchronization primitives. You'll need to import it.
  • The context package is essential for this challenge. You'll need to import it.
Loading editor...
go