Go Task Scheduler
This challenge asks you to implement a basic task scheduler in Go. A task scheduler allows you to schedule functions (tasks) to be executed at specific times or intervals. This is a fundamental component in many applications, such as background job processing, cron-like scheduling, and event-driven systems.
Problem Description
You are to create a TaskScheduler struct in Go that can schedule and execute functions. The scheduler should support the following functionalities:
- Schedule a Task: The
ScheduleTaskmethod should accept a function (task), a name (taskName- string), and a schedule (schedule- a string representing the schedule). The schedule format should be "minute hour day_of_month month day_of_week". This format is consistent with cron expressions. For example, "0 0 * * *" schedules a task to run every day at midnight. - Run the Scheduler: The
Runmethod should start the scheduler, continuously monitoring the current time and executing any scheduled tasks that are due. The scheduler should run indefinitely until explicitly stopped. - Stop the Scheduler: The
Stopmethod should gracefully stop the scheduler, preventing it from scheduling or executing any further tasks. - Task Execution: When a task's scheduled time matches the current time, the task function should be executed.
- Error Handling: The scheduler should handle potential errors gracefully, such as invalid schedule formats. Invalid schedules should be logged (using
log.Println- you can import thelogpackage) and the task should not be scheduled.
Key Requirements:
- Use the
timepackage for time-related operations. - The scheduler should be thread-safe. (Consider using
sync.Mutexif necessary, though for this basic implementation, it might not be strictly required if you're careful about concurrent access). - The scheduler should not block the main thread. Use goroutines to handle task execution and scheduling.
- The schedule format must be strictly adhered to. Any deviation will be considered an invalid schedule.
Expected Behavior:
- Tasks should be executed precisely at the scheduled times.
- The scheduler should continue to run even if some tasks fail to execute (e.g., due to panics within the task function).
- The scheduler should log errors related to invalid schedules.
- The scheduler should stop gracefully when the
Stopmethod is called.
Edge Cases to Consider:
- Invalid schedule formats (e.g., missing fields, incorrect values).
- Tasks scheduled for the past (should not be executed immediately).
- Tasks scheduled for the future.
- Tasks scheduled to run frequently (e.g., every minute).
- Tasks that panic during execution.
Examples
Example 1:
Input:
task: func() { println("Task 1 executed") }
taskName: "TaskOne"
schedule: "0 0 * * *"
Output: The task "TaskOne" will be executed every day at midnight. The scheduler will continue running indefinitely, executing this task daily.
Example 2:
Input:
task: func() { println("Task 2 executed") }
taskName: "TaskTwo"
schedule: "0 12 * * 1"
Output: The task "TaskTwo" will be executed every Monday at noon. The scheduler will continue running indefinitely, executing this task weekly.
Example 3: (Edge Case - Invalid Schedule)
Input:
task: func() { println("Task 3 executed") }
taskName: "TaskThree"
schedule: "invalid schedule"
Output: The scheduler will log an error message: "Invalid schedule format: invalid schedule". The task "TaskThree" will not be scheduled.
Constraints
- The schedule format must strictly adhere to "minute hour day_of_month month day_of_week".
- The scheduler should be able to handle at least 10 scheduled tasks concurrently.
- The scheduler should not consume excessive CPU resources when idle.
- The
timepackage functions should be used for time calculations. - The task functions should be simple (no external dependencies or complex operations).
Notes
- Consider using a separate goroutine for each task execution to prevent blocking.
- You can use the
time.Parsefunction (or a similar parsing method) to validate and parse the schedule string. Be sure to handle errors from the parsing process. - Think about how to represent the schedule internally in a way that allows for efficient comparison with the current time.
- The
Runmethod should continuously monitor the time and execute tasks. A simpletime.Sleepwith a short duration can be used to avoid busy-waiting. - Focus on the core scheduling logic. Error handling and logging are important, but the primary goal is to correctly schedule and execute tasks.
- You don't need to implement a full-fledged cron library; a basic implementation that adheres to the specified format is sufficient.