|
| 1 | +package task_scheduler |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "time" |
| 6 | +) |
| 7 | + |
| 8 | +// Task represents a scheduled job. |
| 9 | +type Task struct { |
| 10 | + ID int |
| 11 | + Name string |
| 12 | + Scheduled time.Time |
| 13 | + Execute func() |
| 14 | +} |
| 15 | + |
| 16 | +// SchedulerError is a typed error returned by scheduler operations. |
| 17 | +type SchedulerError struct { |
| 18 | + Code int |
| 19 | + Message string |
| 20 | +} |
| 21 | + |
| 22 | +func (e *SchedulerError) Error() string { |
| 23 | + return fmt.Sprintf("code=%d: %s", e.Code, e.Message) |
| 24 | +} |
| 25 | + |
| 26 | +// TaskScheduler holds scheduled tasks and next ID. |
| 27 | +type TaskScheduler struct { |
| 28 | + tasks []*Task |
| 29 | + nextID int |
| 30 | +} |
| 31 | + |
| 32 | +// NewTaskScheduler initializes and returns a TaskScheduler. |
| 33 | +func NewTaskScheduler() *TaskScheduler { |
| 34 | + return &TaskScheduler{ |
| 35 | + tasks: make([]*Task, 0), |
| 36 | + nextID: 1, |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +// AddTask validates input and appends a new task with auto-increment ID. |
| 41 | +// Returns the created Task and nil error on success. |
| 42 | +// If name is empty returns SchedulerError with Code 1. |
| 43 | +func (ts *TaskScheduler) AddTask(name string, scheduled time.Time, execFn func()) (*Task, *SchedulerError) { |
| 44 | + if name == "" { |
| 45 | + return nil, &SchedulerError{ |
| 46 | + Code: 1, |
| 47 | + Message: "task name cannot be empty", |
| 48 | + } |
| 49 | + } |
| 50 | + task := &Task{ |
| 51 | + ID: ts.nextID, |
| 52 | + Name: name, |
| 53 | + Scheduled: scheduled, |
| 54 | + Execute: execFn, |
| 55 | + } |
| 56 | + ts.tasks = append(ts.tasks, task) |
| 57 | + ts.nextID++ |
| 58 | + return task, nil |
| 59 | +} |
| 60 | + |
| 61 | +// GetTask finds a task by ID. If not found returns SchedulerError with Code 2. |
| 62 | +func (ts *TaskScheduler) GetTask(id int) (*Task, *SchedulerError) { |
| 63 | + for _, t := range ts.tasks { |
| 64 | + if t.ID == id { |
| 65 | + return t, nil |
| 66 | + } |
| 67 | + } |
| 68 | + return nil, &SchedulerError{ |
| 69 | + Code: 2, |
| 70 | + Message: "task not found", |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +// TaskIterator iterates over tasks in insertion order. |
| 75 | +type TaskIterator struct { |
| 76 | + scheduler *TaskScheduler |
| 77 | + currentIndex int |
| 78 | +} |
| 79 | + |
| 80 | +// Iterator returns a new TaskIterator for the scheduler. |
| 81 | +func (ts *TaskScheduler) Iterator() *TaskIterator { |
| 82 | + return &TaskIterator{ |
| 83 | + scheduler: ts, |
| 84 | + currentIndex: 0, |
| 85 | + } |
| 86 | +} |
| 87 | + |
| 88 | +// Next returns the next task and true if available, otherwise nil,false. |
| 89 | +func (it *TaskIterator) Next() (*Task, bool) { |
| 90 | + if it.scheduler == nil { |
| 91 | + return nil, false |
| 92 | + } |
| 93 | + if it.currentIndex >= len(it.scheduler.tasks) { |
| 94 | + return nil, false |
| 95 | + } |
| 96 | + t := it.scheduler.tasks[it.currentIndex] |
| 97 | + it.currentIndex++ |
| 98 | + return t, true |
| 99 | +} |
| 100 | + |
| 101 | +// RunScheduledTasks executes tasks whose Scheduled time is <= now. |
| 102 | +// This implementation calls task.Execute synchronously in the current goroutine. |
| 103 | +func (ts *TaskScheduler) RunScheduledTasks() { |
| 104 | + now := time.Now() |
| 105 | + for _, t := range ts.tasks { |
| 106 | + if !t.Scheduled.After(now) { |
| 107 | + if t.Execute != nil { |
| 108 | + t.Execute() |
| 109 | + } |
| 110 | + } |
| 111 | + } |
| 112 | +} |
0 commit comments