Skip to content

Commit d1d380a

Browse files
authored
Rewrite scheduler (#89)
* scheduler: Rewrite
1 parent 0784fe7 commit d1d380a

File tree

11 files changed

+328
-438
lines changed

11 files changed

+328
-438
lines changed

scheduler/clock.go

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ func (c Clock) IsMatched(t time.Time) bool {
143143
}
144144

145145
func (c Clock) Next(t time.Time) (next time.Time) {
146+
t = t.Truncate(time.Second)
147+
if c.IsMatched(t) {
148+
t = t.Add(time.Second)
149+
}
146150
year, month, day := t.Date()
147151
var hour, min, sec int
148152
if c.sec {
@@ -160,7 +164,7 @@ func (c Clock) Next(t time.Time) (next time.Time) {
160164
} else {
161165
hour = t.Hour()
162166
}
163-
switch next = time.Date(year, month, day, hour, min, sec, 0, t.Location()); t.Truncate(time.Second).Compare(next) {
167+
switch next = time.Date(year, month, day, hour, min, sec, 0, t.Location()); t.Compare(next) {
164168
case 1:
165169
if !c.sec {
166170
next = next.Add(-time.Duration(sec) * time.Second)
@@ -190,18 +194,6 @@ func (c Clock) Next(t time.Time) (next time.Time) {
190194
}
191195
}
192196

193-
func (c Clock) TickerDuration() time.Duration {
194-
if !c.sec {
195-
return time.Second
196-
} else if !c.min {
197-
return time.Minute
198-
} else if !c.hour {
199-
return time.Hour
200-
} else {
201-
return 24 * time.Hour
202-
}
203-
}
204-
205197
func (c Clock) String() string {
206198
var hour, min, sec string
207199
if !c.hour {
@@ -241,7 +233,7 @@ func (s clockSched) IsMatched(t time.Time) bool {
241233

242234
func (s clockSched) Next(t time.Time) time.Time {
243235
if s.IsMatched(t) {
244-
return t
236+
t = t.Add(time.Second)
245237
}
246238
start, end := s.start.Clock, s.end.Clock
247239
for c := AtClock(t.Clock()); c.Compare(start) != -1 && c.Compare(end) != 1; c.Clock = c.Add(time.Second) {

scheduler/clock_test.go

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ func TestClock(t *testing.T) {
1818
t.Error("expected false: got true")
1919
}
2020
s = ScheduleFromString("7:00")
21-
if res := s.TickerDuration(); res != 24*time.Hour {
22-
t.Errorf("expected 24h; got %v", res)
23-
}
2421
if res := s.Next(AtClock(6, 0, 0).Time()).Format("15:04:05"); res != "07:00:00" {
2522
t.Errorf("expected 07:00:00; got %q", res)
2623
}
@@ -34,11 +31,11 @@ func TestClockNext1(t *testing.T) {
3431
expected time.Duration
3532
}{
3633
{AtClock(0, 0, 0), "00:00:00", 11*time.Hour + 29*time.Minute + 30*time.Second},
37-
{AtClock(-1, -1, -1), "12:30:30", 0},
38-
{AtClock(-1, -1, 30), "12:30:30", 0},
39-
{AtClock(-1, 30, -1), "12:30:30", 0},
40-
{AtClock(12, -1, -1), "12:30:30", 0},
41-
{AtClock(12, -1, 30), "12:30:30", 0},
34+
{AtClock(-1, -1, -1), "12:30:31", time.Second},
35+
{AtClock(-1, -1, 30), "12:31:30", time.Minute},
36+
{AtClock(-1, 30, -1), "12:30:31", time.Second},
37+
{AtClock(12, -1, -1), "12:30:31", time.Second},
38+
{AtClock(12, -1, 30), "12:31:30", time.Minute},
4239
{AtClock(-1, -1, 15), "12:31:15", 45 * time.Second},
4340
{AtClock(-1, -1, 45), "12:30:45", 15 * time.Second},
4441
{AtClock(-1, 15, -1), "13:15:00", 44*time.Minute + 30*time.Second},
@@ -65,7 +62,7 @@ func TestClockNext2(t *testing.T) {
6562
s string
6663
d time.Duration
6764
}{
68-
{AtClock(0, 0, -1), AtClock(0, 0, 59).Time(), "00:00:59", 0},
65+
{AtClock(0, 0, -1), AtClock(0, 0, 59).Time(), "00:00:00", 23*time.Hour + 59*time.Minute + time.Second},
6966
{AtClock(0, -1, 0), AtClock(0, 59, 59).Time(), "00:00:00", 23*time.Hour + time.Second},
7067
{AtClock(-1, 0, 0), AtClock(23, 59, 0).Time(), "00:00:00", time.Minute},
7168
{AtClock(0, -1, 0), AtClock(0, 0, 59).Time(), "00:01:00", time.Second},
@@ -81,34 +78,16 @@ func TestClockNext2(t *testing.T) {
8178
}
8279
}
8380

84-
func TestClockTickerDuration(t *testing.T) {
85-
for _, testcase := range []struct {
86-
clock *Clock
87-
expected time.Duration
88-
}{
89-
{AtClock(1, 0, 0), 24 * time.Hour},
90-
{AtClock(-1, 2, 0), time.Hour},
91-
{AtClock(0, -1, 3), time.Minute},
92-
{AtClock(4, 0, -1), time.Second},
93-
{AtClock(-1, 5, -1), time.Second},
94-
{AtClock(-1, -1, -1), time.Second},
95-
} {
96-
if res := testcase.clock.TickerDuration(); res != testcase.expected {
97-
t.Errorf("%s expected %v; got %v", testcase.clock, testcase.expected, res)
98-
}
99-
}
100-
}
101-
10281
func TestClockSchedule(t *testing.T) {
10382
s := ClockSchedule(AtHour(9).Minute(30), AtHour(15), 2*time.Minute)
10483
for _, testcase := range []struct {
10584
clock *Clock
10685
time string
10786
expected bool
10887
}{
109-
{AtClock(9, 30, 0), "09:30:00", true},
110-
{AtClock(15, 0, 0), "15:00:00", true},
111-
{AtClock(13, 0, 0), "13:00:00", true},
88+
{AtClock(9, 30, 0), "09:32:00", true},
89+
{AtClock(15, 0, 0), "09:30:00", true},
90+
{AtClock(13, 0, 0), "13:02:00", true},
11291
{ClockFromString("9:29"), "09:30:00", false},
11392
{ClockFromString("9:31"), "09:32:00", false},
11493
{ClockFromString("16:00:00"), "09:30:00", false},

scheduler/complex.go

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ var (
1616
type complexSched interface {
1717
IsMatched(time.Time) bool
1818
Next(time.Time) time.Time
19-
TickerDuration() time.Duration
2019
String() string
2120

2221
init(t time.Time)
@@ -69,15 +68,6 @@ func (s multiSched) Next(t time.Time) (next time.Time) {
6968
return
7069
}
7170

72-
func (s multiSched) TickerDuration() time.Duration {
73-
if l := len(s); l == 0 {
74-
return 0
75-
} else if l == 1 {
76-
return s[0].TickerDuration()
77-
}
78-
return time.Second
79-
}
80-
8171
func (s multiSched) String() string {
8272
switch len(s) {
8373
case 0:
@@ -129,34 +119,17 @@ func (s condSched) Next(t time.Time) (next time.Time) {
129119
} else if l == 1 {
130120
return s[0].Next(t)
131121
}
132-
var start time.Time
133-
var duration time.Duration
134-
for _, s := range s {
135-
if d := s.TickerDuration(); d > duration {
136-
duration = d
137-
start = s.Next(t)
138-
} else if d == duration {
139-
if next := s.Next(t); next.Before(start) {
140-
start = next
141-
}
142-
}
122+
if s.IsMatched(t) {
123+
t = t.Add(time.Second)
143124
}
144-
for next = start; !s.IsMatched(next); next = next.Add(duration) {
125+
for next = t.Truncate(time.Second); !s.IsMatched(next); next = next.Add(time.Second) {
145126
if next.Sub(t) >= time.Hour*24*366 {
146127
return time.Time{}
147128
}
148129
}
149130
return
150131
}
151132

152-
func (s condSched) TickerDuration() time.Duration {
153-
var res time.Duration
154-
for _, i := range s {
155-
res = gcd(res, i.TickerDuration())
156-
}
157-
return res
158-
}
159-
160133
func (s condSched) String() string {
161134
switch len(s) {
162135
case 0:

scheduler/complex_test.go

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
package scheduler
22

3-
import (
4-
"testing"
5-
"time"
6-
)
3+
import "testing"
74

85
func TestMultiSchedule(t *testing.T) {
96
s := MultiSchedule(AtHour(3), AtMinute(4), AtSecond(5))
10-
if res := s.Next(time.Time{}).Format("15:04:05"); res != "00:00:05" {
11-
t.Fatalf("expected 00:00:05: got %q", res)
12-
}
137
for _, testcase := range []struct {
148
clock *Clock
159
expected bool
@@ -25,14 +19,27 @@ func TestMultiSchedule(t *testing.T) {
2519
}
2620
}
2721

22+
func TestMultiScheduleNext(t *testing.T) {
23+
s := MultiSchedule(AtHour(3), AtMinute(4), AtSecond(5))
24+
for _, testcase := range []struct {
25+
t string
26+
next string
27+
}{
28+
{"2000/01/01 00:00:00", "2000/01/01 00:00:05"},
29+
{"2000/01/01 00:00:05", "2000/01/01 00:01:05"},
30+
{"2000/01/01 00:03:05", "2000/01/01 00:04:00"},
31+
{"2000/01/01 00:04:00", "2000/01/01 00:04:05"},
32+
{"2000/01/01 02:59:05", "2000/01/01 03:00:00"},
33+
{"2000/01/01 03:00:00", "2000/01/01 03:00:05"},
34+
} {
35+
if res := s.Next(parse(testcase.t)).Format(format); res != testcase.next {
36+
t.Errorf("%s expected %v; got %v", testcase.t, testcase.next, res)
37+
}
38+
}
39+
}
40+
2841
func TestConditionSchedule(t *testing.T) {
2942
s := ConditionSchedule(Weekdays, MultiSchedule(AtClock(9, 30, 0), AtHour(15)))
30-
if d := s.TickerDuration(); d != time.Second {
31-
t.Fatalf("expected 1s: got %s", d)
32-
}
33-
if res := s.Next(time.Time{}).Format("15:04:05"); res != "09:30:00" {
34-
t.Fatalf("expected 00:00:01: got %q", res)
35-
}
3643
for _, testcase := range []struct {
3744
clock *Clock
3845
expected bool
@@ -47,3 +54,20 @@ func TestConditionSchedule(t *testing.T) {
4754
}
4855
}
4956
}
57+
58+
func TestConditionScheduleNext(t *testing.T) {
59+
s := ConditionSchedule(Weekdays, MultiSchedule(AtClock(9, 30, 0), AtHour(15)))
60+
for _, testcase := range []struct {
61+
t string
62+
next string
63+
}{
64+
{"2000/01/01 00:00:00", "2000/01/03 09:30:00"},
65+
{"2000/01/03 09:30:00", "2000/01/03 15:00:00"},
66+
{"2000/01/03 15:00:00", "2000/01/04 09:30:00"},
67+
{"2000/01/07 15:00:00", "2000/01/10 09:30:00"},
68+
} {
69+
if res := s.Next(parse(testcase.t)).Format(format); res != testcase.next {
70+
t.Errorf("%s expected %v; got %v", testcase.t, testcase.next, res)
71+
}
72+
}
73+
}

scheduler/init.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package scheduler
2+
3+
import (
4+
"time"
5+
6+
"github.com/sunshineplan/utils/container"
7+
)
8+
9+
var subscriber = container.NewMap[chan Event, time.Time]()
10+
11+
type Event struct {
12+
Time time.Time
13+
Goal time.Time
14+
Missed bool
15+
}
16+
17+
func init() {
18+
go func() {
19+
for t := range time.NewTicker(time.Second).C {
20+
t = t.Truncate(time.Second)
21+
go subscriber.Range(func(k chan Event, v time.Time) bool {
22+
switch v.Compare(t) {
23+
case -1:
24+
k <- Event{t, v, true}
25+
case 0:
26+
k <- Event{t, v, false}
27+
}
28+
return true
29+
})
30+
}
31+
}()
32+
}
33+
34+
func subscribe(t time.Time, c chan Event) {
35+
subscriber.Swap(c, t.Truncate(time.Second))
36+
}
37+
38+
func unsubscribe(c chan Event) {
39+
subscriber.Delete(c)
40+
}

scheduler/misc.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

scheduler/notify.go

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)