Skip to content

Commit 779c534

Browse files
feat(exercises): add solution for 30_task_scheduler (#125)
1 parent 23993a6 commit 779c534

1 file changed

Lines changed: 112 additions & 0 deletions

File tree

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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

Comments
 (0)