Hone logo
Hone
Problems

Custom Task Scheduler in Go

This challenge asks you to implement a simple task scheduler in Go. A task scheduler allows you to execute functions (tasks) at specific times or intervals. This is a fundamental component in many applications, such as background job processing, periodic data updates, and event-driven systems.

Problem Description

You are to create a Scheduler struct that can schedule and execute tasks. The scheduler should support the following functionalities:

  • Adding Tasks: A method Schedule that accepts a function (task) and a schedule (either a specific time or an interval).
  • Task Types: The scheduler should handle two types of schedules:
    • One-time execution: The task is executed only once at a specified time.
    • Recurring execution: The task is executed repeatedly at a specified interval (in seconds).
  • Execution: The scheduler should run in a goroutine and execute the scheduled tasks at their designated times.
  • Cancellation: A method Stop that gracefully stops the scheduler and prevents any further task executions.
  • Time Handling: Use Go's time package for time-related operations.

Key Requirements:

  • The scheduler should be thread-safe. Multiple tasks can be scheduled concurrently.
  • The scheduler should handle potential errors during task execution. If a task panics, the scheduler should log the error but continue executing other scheduled tasks.
  • The scheduler should not block the main goroutine.

Expected Behavior:

The scheduler should continuously monitor the current time and execute tasks that are due. Recurring tasks should be executed repeatedly at the specified interval. The Stop method should terminate the scheduler's goroutine cleanly.

Edge Cases to Consider:

  • Tasks scheduled for the past should be executed immediately.
  • What happens if a task takes longer to execute than its interval? (Consider whether to allow overlap or not - for this challenge, overlapping is acceptable).
  • How to handle invalid schedule times (e.g., negative intervals). For simplicity, you can ignore invalid times.
  • What happens if the scheduler is stopped while a task is running? The task should be allowed to complete.

Examples

Example 1: One-time Task

Input:
- Schedule a function `printMessage` to execute at time.Now().Add(5 * time.Second)
  where printMessage() prints "One-time task executed!".
- Run the scheduler for 10 seconds.
Output:
After 5 seconds, "One-time task executed!" is printed to the console.
Explanation: The scheduler waits until 5 seconds after the current time and then executes the `printMessage` function.

Example 2: Recurring Task

Input:
- Schedule a function `printInterval` to execute every 2 seconds, where printInterval() prints "Recurring task executed!".
- Run the scheduler for 8 seconds.
Output:
"Recurring task executed!" is printed to the console every 2 seconds for 8 seconds.
Explanation: The scheduler executes the `printInterval` function every 2 seconds.

Example 3: Task Error Handling

Input:
- Schedule a function `panicTask` to execute every 1 second, where panicTask() panics.
- Schedule a function `normalTask` to execute every 3 seconds, where normalTask() prints "Normal task executed!".
- Run the scheduler for 5 seconds.
Output:
"Normal task executed!" is printed once.
The scheduler logs the panic from `panicTask` but continues to execute `normalTask`.
Explanation: The scheduler handles the panic from `panicTask` gracefully and continues to execute other tasks.

Constraints

  • The scheduler should be able to handle at least 100 scheduled tasks concurrently.
  • The time resolution for recurring tasks should be accurate to within 1 second.
  • The scheduler's memory usage should be reasonable (avoid excessive memory allocation).
  • The Schedule method should be able to handle schedules up to 1 year in the future.

Notes

  • Consider using channels to communicate between the scheduler's goroutine and the main goroutine for stopping the scheduler.
  • Think about how to represent the schedule (e.g., using a struct with fields for time and interval).
  • Use appropriate synchronization primitives (e.g., mutexes) to ensure thread safety.
  • Error handling is crucial. Don't let a single task failure bring down the entire scheduler.
  • Focus on clarity and maintainability of your code. Well-commented code is appreciated.
  • You don't need to implement a persistent storage mechanism for tasks. Tasks should be lost when the scheduler is stopped.
Loading editor...
go