-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
code.go
92 lines (80 loc) · 1.83 KB
/
code.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Copyright (c) 2020 Shivam Rathore. All rights reserved.
// Use of this source code is governed by MIT License that
// can be found in the LICENSE file.
// Package solution contains Solution to Challenge #010, run
// TestSolution for test cases
package _010
import (
"errors"
"sync"
"time"
)
var ErrSchedulerStopped = errors.New("scheduler has been stopped")
type Scheduler interface {
// Schedule schedules fn after dur time with returned id until
// it is not stopped using StopScheduling
Schedule(fn func(), dur time.Duration) (int, error)
// StopScheduling: stops Scheduler from scheduling any more, using
// Schedule after StopScheduling() will return ErrSchedulerStopped
StopScheduling()
// Ack: helps acknowledge that the Schedule function is finished
// using the int::id provided at time of Schedule()
Ack() <-chan int
}
// NewScheduler creates a new scheduler
func NewScheduler() Scheduler {
return newRunner()
}
type runner struct {
wg sync.WaitGroup
list chan *job
ack chan int
size int // if -1 means closed
}
func (r *runner) Schedule(fn func(), dur time.Duration) (int, error) {
if r.size == -1 {
return 0, ErrSchedulerStopped
}
r.size++
r.list <- &job{dur: dur, fn: fn, id: r.size}
return r.size, nil
}
func (r *runner) StopScheduling() {
defer close(r.ack)
r.size = -1
close(r.list)
r.wg.Done() // self runner goroutine
r.wg.Wait()
}
func (r *runner) Ack() <-chan int {
return r.ack
}
func newRunner() *runner {
rn := &runner{
wg: sync.WaitGroup{},
list: make(chan *job),
ack: make(chan int),
}
rn.run()
return rn
}
func (r *runner) run() {
r.wg.Add(1)
go func() {
for job := range r.list {
job := job
r.wg.Add(1)
go func() {
defer r.wg.Done()
time.Sleep(job.dur)
job.fn()
r.ack <- job.id
}()
}
}()
}
type job struct {
id int
fn func()
dur time.Duration
}