rufus-scheduler 2.0.6 → 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/CHANGELOG.txt +6 -0
- data/CREDITS.txt +2 -0
- data/README.rdoc +45 -12
- data/Rakefile +27 -22
- data/lib/rufus/sc/cronline.rb +61 -44
- data/lib/rufus/sc/jobqueues.rb +6 -7
- data/lib/rufus/sc/jobs.rb +27 -10
- data/lib/rufus/sc/rtime.rb +46 -38
- data/lib/rufus/sc/scheduler.rb +33 -23
- data/lib/rufus/sc/version.rb +1 -1
- data/lib/rufus/scheduler.rb +2 -2
- data/rufus-scheduler.gemspec +29 -13
- data/spec/at_in_spec.rb +8 -9
- data/spec/at_spec.rb +25 -26
- data/spec/blocking_spec.rb +7 -7
- data/spec/cron_spec.rb +23 -23
- data/spec/cronline_spec.rb +175 -40
- data/spec/every_spec.rb +71 -33
- data/spec/exception_spec.rb +11 -12
- data/spec/in_spec.rb +35 -36
- data/spec/rtime_spec.rb +47 -47
- data/spec/schedulable_spec.rb +15 -15
- data/spec/scheduler_spec.rb +14 -15
- data/spec/spec_base.rb +6 -13
- data/spec/stress_schedule_unschedule_spec.rb +124 -120
- data/spec/timeout_spec.rb +24 -24
- metadata +32 -10
- data/spec/spec.rb +0 -14
data/spec/cronline_spec.rb
CHANGED
@@ -5,63 +5,198 @@
|
|
5
5
|
# Sat Mar 21 12:55:27 JST 2009
|
6
6
|
#
|
7
7
|
|
8
|
-
require File.dirname(__FILE__)
|
9
|
-
|
10
|
-
|
11
|
-
def cl (cronline_string)
|
12
|
-
Rufus::CronLine.new(cronline_string)
|
13
|
-
end
|
8
|
+
require File.join(File.dirname(__FILE__), 'spec_base')
|
14
9
|
|
15
10
|
|
16
11
|
describe Rufus::CronLine do
|
17
12
|
|
18
|
-
def
|
13
|
+
def cl(cronline_string)
|
14
|
+
Rufus::CronLine.new(cronline_string)
|
15
|
+
end
|
19
16
|
|
20
|
-
|
17
|
+
def match(line, time)
|
18
|
+
cl(line).matches?(time).should == true
|
19
|
+
end
|
20
|
+
def to_a(line, array)
|
21
|
+
cl(line).to_array.should == array
|
21
22
|
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
should '* * * * *', [ [0], nil, nil, nil, nil, nil ]
|
26
|
-
should '10-12 * * * *', [ [0], [10, 11, 12], nil, nil, nil, nil ]
|
27
|
-
should '* * * * sun,mon', [ [0], nil, nil, nil, nil, [0, 1] ]
|
28
|
-
should '* * * * mon-wed', [ [0], nil, nil, nil, nil, [1, 2, 3] ]
|
29
|
-
should '* * * * 7', [ [0], nil, nil, nil, nil, [0] ]
|
30
|
-
should '* * * * 0', [ [0], nil, nil, nil, nil, [0] ]
|
31
|
-
should '* * * * 0,1', [ [0], nil, nil, nil, nil, [0,1] ]
|
32
|
-
should '* * * * 7,1', [ [0], nil, nil, nil, nil, [0,1] ]
|
33
|
-
should '* * * * 7,0', [ [0], nil, nil, nil, nil, [0] ]
|
34
|
-
should '* * * * sun,2-4', [ [0], nil, nil, nil, nil, [0, 2, 3, 4] ]
|
35
|
-
|
36
|
-
should '* * * * sun,mon-tue', [ [0], nil, nil, nil, nil, [0, 1, 2] ]
|
37
|
-
|
38
|
-
should '* * * * * *', [ nil, nil, nil, nil, nil, nil ]
|
39
|
-
should '1 * * * * *', [ [1], nil, nil, nil, nil, nil ]
|
40
|
-
should '7 10-12 * * * *', [ [7], [10, 11, 12], nil, nil, nil, nil ]
|
41
|
-
should '1-5 * * * * *', [ [1,2,3,4,5], nil, nil, nil, nil, nil ]
|
24
|
+
def local(*args)
|
25
|
+
Time.local(*args)
|
42
26
|
end
|
43
|
-
|
27
|
+
def utc(*args)
|
28
|
+
Time.utc(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.new' do
|
32
|
+
|
33
|
+
it 'interprets cron strings correctly' do
|
34
|
+
|
35
|
+
to_a '* * * * *', [ [0], nil, nil, nil, nil, nil, nil ]
|
36
|
+
to_a '10-12 * * * *', [ [0], [10, 11, 12], nil, nil, nil, nil, nil ]
|
37
|
+
to_a '* * * * sun,mon', [ [0], nil, nil, nil, nil, [0, 1], nil ]
|
38
|
+
to_a '* * * * mon-wed', [ [0], nil, nil, nil, nil, [1, 2, 3], nil ]
|
39
|
+
to_a '* * * * 7', [ [0], nil, nil, nil, nil, [0], nil ]
|
40
|
+
to_a '* * * * 0', [ [0], nil, nil, nil, nil, [0], nil ]
|
41
|
+
to_a '* * * * 0,1', [ [0], nil, nil, nil, nil, [0,1], nil ]
|
42
|
+
to_a '* * * * 7,1', [ [0], nil, nil, nil, nil, [0,1], nil ]
|
43
|
+
to_a '* * * * 7,0', [ [0], nil, nil, nil, nil, [0], nil ]
|
44
|
+
to_a '* * * * sun,2-4', [ [0], nil, nil, nil, nil, [0, 2, 3, 4], nil ]
|
45
|
+
|
46
|
+
to_a '* * * * sun,mon-tue', [ [0], nil, nil, nil, nil, [0, 1, 2], nil ]
|
47
|
+
|
48
|
+
to_a '* * * * * *', [ nil, nil, nil, nil, nil, nil, nil ]
|
49
|
+
to_a '1 * * * * *', [ [1], nil, nil, nil, nil, nil, nil ]
|
50
|
+
to_a '7 10-12 * * * *', [ [7], [10, 11, 12], nil, nil, nil, nil, nil ]
|
51
|
+
to_a '1-5 * * * * *', [ [1,2,3,4,5], nil, nil, nil, nil, nil, nil ]
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'interprets cron strings with TZ correctly' do
|
55
|
+
|
56
|
+
to_a '* * * * * EST', [ [0], nil, nil, nil, nil, nil, 'EST' ]
|
57
|
+
to_a '* * * * * * EST', [ nil, nil, nil, nil, nil, nil, 'EST' ]
|
58
|
+
|
59
|
+
lambda { cl '* * * * * NotATimeZone' }.should raise_error
|
60
|
+
lambda { cl '* * * * * * NotATimeZone' }.should raise_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#next_time' do
|
65
|
+
|
66
|
+
def nt(cronline, now)
|
67
|
+
Rufus::CronLine.new(cronline).next_time(now)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'computes the next occurence correctly' do
|
71
|
+
|
72
|
+
now = Time.at(0).getutc # Thu Jan 01 00:00:00 UTC 1970
|
73
|
+
|
74
|
+
nt('* * * * *', now).should == now + 60
|
75
|
+
nt('* * * * sun', now).should == now + 259200
|
76
|
+
nt('* * * * * *', now).should == now + 1
|
77
|
+
nt('* * 13 * fri', now).should == now + 3715200
|
78
|
+
|
79
|
+
nt('10 12 13 12 *', now).should == now + 29938200
|
80
|
+
# this one is slow (1 year == 3 seconds)
|
81
|
+
|
82
|
+
nt('0 0 * * thu', now).should == now + 604800
|
83
|
+
|
84
|
+
now = local(2008, 12, 31, 23, 59, 59, 0)
|
85
|
+
|
86
|
+
nt('* * * * *', now).should == now + 1
|
87
|
+
end
|
44
88
|
|
45
|
-
|
89
|
+
#
|
90
|
+
# the specs that follow are from Tanzeeb Khalili
|
91
|
+
#
|
92
|
+
|
93
|
+
it 'computes the next occurence correctly in UTC (TZ not specified)' do
|
94
|
+
|
95
|
+
now = utc(1970, 1, 1)
|
96
|
+
|
97
|
+
nt('* * * * *', now).should == utc(1970, 1, 1, 0, 1)
|
98
|
+
nt('* * * * sun', now).should == utc(1970, 1, 4)
|
99
|
+
nt('* * * * * *', now).should == utc(1970, 1, 1, 0, 0, 1)
|
100
|
+
nt('* * 13 * fri', now).should == utc(1970, 2, 13)
|
101
|
+
|
102
|
+
nt('10 12 13 12 *', now).should == utc(1970, 12, 13, 12, 10)
|
103
|
+
# this one is slow (1 year == 3 seconds)
|
104
|
+
nt('* * 1 6 *', now).should == utc(1970, 6, 1)
|
105
|
+
|
106
|
+
nt('0 0 * * thu', now).should == utc(1970, 1, 8)
|
107
|
+
end
|
46
108
|
|
47
|
-
|
109
|
+
it 'computes the next occurence correctly in local TZ (TZ not specified)' do
|
48
110
|
|
49
|
-
|
111
|
+
now = local(1970, 1, 1)
|
50
112
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
113
|
+
nt('* * * * *', now).should == local(1970, 1, 1, 0, 1)
|
114
|
+
nt('* * * * sun', now).should == local(1970, 1, 4)
|
115
|
+
nt('* * * * * *', now).should == local(1970, 1, 1, 0, 0, 1)
|
116
|
+
nt('* * 13 * fri', now).should == local(1970, 2, 13)
|
55
117
|
|
56
|
-
|
57
|
-
|
118
|
+
nt('10 12 13 12 *', now).should == local(1970, 12, 13, 12, 10)
|
119
|
+
# this one is slow (1 year == 3 seconds)
|
120
|
+
nt('* * 1 6 *', now).should == local(1970, 6, 1)
|
58
121
|
|
59
|
-
|
122
|
+
nt('0 0 * * thu', now).should == local(1970, 1, 8)
|
123
|
+
end
|
60
124
|
|
61
|
-
|
125
|
+
it 'computes the next occurence correctly in UTC (TZ specified)' do
|
62
126
|
|
63
|
-
|
127
|
+
zone = 'Europe/Stockholm'
|
128
|
+
tz = TZInfo::Timezone.get(zone)
|
129
|
+
now = tz.local_to_utc(local(1970, 1, 1))
|
130
|
+
# Midnight in zone, UTC
|
131
|
+
|
132
|
+
nt("* * * * * #{zone}", now).should == utc(1969, 12, 31, 23, 1)
|
133
|
+
nt("* * * * sun #{zone}", now).should == utc(1970, 1, 3, 23)
|
134
|
+
nt("* * * * * * #{zone}", now).should == utc(1969, 12, 31, 23, 0, 1)
|
135
|
+
nt("* * 13 * fri #{zone}", now).should == utc(1970, 2, 12, 23)
|
136
|
+
|
137
|
+
nt("10 12 13 12 * #{zone}", now).should == utc(1970, 12, 13, 11, 10)
|
138
|
+
nt("* * 1 6 * #{zone}", now).should == utc(1970, 5, 31, 23)
|
139
|
+
|
140
|
+
nt("0 0 * * thu #{zone}", now).should == utc(1970, 1, 7, 23)
|
141
|
+
end
|
142
|
+
|
143
|
+
#it 'computes the next occurence correctly in local TZ (TZ specified)' do
|
144
|
+
# zone = 'Europe/Stockholm'
|
145
|
+
# tz = TZInfo::Timezone.get(zone)
|
146
|
+
# now = tz.local_to_utc(utc(1970, 1, 1)).localtime
|
147
|
+
# # Midnight in zone, local time
|
148
|
+
# nt("* * * * * #{zone}", now).should == local(1969, 12, 31, 18, 1)
|
149
|
+
# nt("* * * * sun #{zone}", now).should == local(1970, 1, 3, 18)
|
150
|
+
# nt("* * * * * * #{zone}", now).should == local(1969, 12, 31, 18, 0, 1)
|
151
|
+
# nt("* * 13 * fri #{zone}", now).should == local(1970, 2, 12, 18)
|
152
|
+
# nt("10 12 13 12 * #{zone}", now).should == local(1970, 12, 13, 6, 10)
|
153
|
+
# nt("* * 1 6 * #{zone}", now).should == local(1970, 5, 31, 19)
|
154
|
+
# nt("0 0 * * thu #{zone}", now).should == local(1970, 1, 7, 18)
|
155
|
+
#end
|
64
156
|
end
|
65
157
|
|
158
|
+
describe '#matches?' do
|
159
|
+
|
160
|
+
it 'matches correctly in UTC (TZ not specified)' do
|
161
|
+
|
162
|
+
match '* * * * *', utc(1970, 1, 1, 0, 1)
|
163
|
+
match '* * * * sun', utc(1970, 1, 4)
|
164
|
+
match '* * * * * *', utc(1970, 1, 1, 0, 0, 1)
|
165
|
+
match '* * 13 * fri', utc(1970, 2, 13)
|
166
|
+
|
167
|
+
match '10 12 13 12 *', utc(1970, 12, 13, 12, 10)
|
168
|
+
match '* * 1 6 *', utc(1970, 6, 1)
|
169
|
+
|
170
|
+
match '0 0 * * thu', utc(1970, 1, 8)
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'matches correctly in local TZ (TZ not specified)' do
|
174
|
+
|
175
|
+
match '* * * * *', local(1970, 1, 1, 0, 1)
|
176
|
+
match '* * * * sun', local(1970, 1, 4)
|
177
|
+
match '* * * * * *', local(1970, 1, 1, 0, 0, 1)
|
178
|
+
match '* * 13 * fri', local(1970, 2, 13)
|
179
|
+
|
180
|
+
match '10 12 13 12 *', local(1970, 12, 13, 12, 10)
|
181
|
+
match '* * 1 6 *', local(1970, 6, 1)
|
182
|
+
|
183
|
+
match '0 0 * * thu', local(1970, 1, 8)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'matches correctly in UTC (TZ specified)' do
|
187
|
+
|
188
|
+
zone = 'Europe/Stockholm'
|
189
|
+
|
190
|
+
match "* * * * * #{zone}", utc(1969, 12, 31, 23, 1)
|
191
|
+
match "* * * * sun #{zone}", utc(1970, 1, 3, 23)
|
192
|
+
match "* * * * * * #{zone}", utc(1969, 12, 31, 23, 0, 1)
|
193
|
+
match "* * 13 * fri #{zone}", utc(1970, 2, 12, 23)
|
194
|
+
|
195
|
+
match "10 12 13 12 * #{zone}", utc(1970, 12, 13, 11, 10)
|
196
|
+
match "* * 1 6 * #{zone}", utc(1970, 5, 31, 23)
|
197
|
+
|
198
|
+
match "0 0 * * thu #{zone}", utc(1970, 1, 7, 23)
|
199
|
+
end
|
200
|
+
end
|
66
201
|
end
|
67
202
|
|
data/spec/every_spec.rb
CHANGED
@@ -5,32 +5,32 @@
|
|
5
5
|
# Sun Mar 22 12:26:07 JST 2009
|
6
6
|
#
|
7
7
|
|
8
|
-
require File.dirname(__FILE__)
|
8
|
+
require File.join(File.dirname(__FILE__), 'spec_base')
|
9
9
|
|
10
10
|
|
11
11
|
describe "#{SCHEDULER_CLASS}#every" do
|
12
12
|
|
13
|
-
before do
|
13
|
+
before(:each) do
|
14
14
|
@s = start_scheduler
|
15
15
|
end
|
16
|
-
after do
|
16
|
+
after(:each) do
|
17
17
|
stop_scheduler(@s)
|
18
18
|
end
|
19
19
|
|
20
|
-
it '
|
20
|
+
it 'has job ids with the class name in it' do
|
21
21
|
|
22
22
|
j0 = @s.every(1) {}
|
23
|
-
j0.job_id.should
|
23
|
+
j0.job_id.should match(/Rufus::Scheduler::EveryJob/)
|
24
24
|
end
|
25
25
|
|
26
|
-
it '
|
26
|
+
it 'computes frequency' do
|
27
27
|
|
28
28
|
job = @s.every '2h1m' do
|
29
29
|
end
|
30
|
-
job.frequency.should
|
30
|
+
job.frequency.should == 7260
|
31
31
|
end
|
32
32
|
|
33
|
-
it '
|
33
|
+
it 'schedules every 1s' do
|
34
34
|
|
35
35
|
var = 0
|
36
36
|
|
@@ -40,10 +40,10 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
40
40
|
|
41
41
|
sleep 3.7
|
42
42
|
|
43
|
-
var.should
|
43
|
+
var.should == 3
|
44
44
|
end
|
45
45
|
|
46
|
-
it '
|
46
|
+
it 'is punctilious' do
|
47
47
|
|
48
48
|
hits = []
|
49
49
|
|
@@ -58,10 +58,10 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
58
58
|
hits.each { |h| f = h; deltas << (f - hh) if hh; hh = f }
|
59
59
|
|
60
60
|
#puts; p deltas
|
61
|
-
deltas.max.should
|
61
|
+
deltas.max.should satisfy { |d| d < 1.200 }
|
62
62
|
end
|
63
63
|
|
64
|
-
it '
|
64
|
+
it 'unschedules' do
|
65
65
|
|
66
66
|
var = 0
|
67
67
|
|
@@ -73,25 +73,25 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
73
73
|
|
74
74
|
@s.unschedule(job.job_id)
|
75
75
|
|
76
|
-
var.should
|
76
|
+
var.should == 2
|
77
77
|
|
78
78
|
sleep 1.7
|
79
79
|
|
80
|
-
var.should
|
80
|
+
var.should == 2
|
81
81
|
end
|
82
82
|
|
83
|
-
it '
|
83
|
+
it 'accepts tags for jobs' do
|
84
84
|
|
85
85
|
job = @s.every '1s', :tags => 'spec' do
|
86
86
|
end
|
87
87
|
|
88
88
|
wait_next_tick
|
89
89
|
|
90
|
-
@s.find_by_tag('spec').size.should
|
91
|
-
@s.find_by_tag('spec').first.job_id.should
|
90
|
+
@s.find_by_tag('spec').size.should == 1
|
91
|
+
@s.find_by_tag('spec').first.job_id.should == job.job_id
|
92
92
|
end
|
93
93
|
|
94
|
-
it '
|
94
|
+
it 'honours :first_at' do
|
95
95
|
|
96
96
|
counter = 0
|
97
97
|
|
@@ -100,13 +100,13 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
100
100
|
end
|
101
101
|
|
102
102
|
sleep 1
|
103
|
-
counter.should
|
103
|
+
counter.should == 0
|
104
104
|
|
105
105
|
sleep 2.5
|
106
|
-
counter.should
|
106
|
+
counter.should == 2
|
107
107
|
end
|
108
108
|
|
109
|
-
it '
|
109
|
+
it 'honours :first_in' do
|
110
110
|
|
111
111
|
counter = 0
|
112
112
|
|
@@ -115,13 +115,13 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
sleep 1
|
118
|
-
counter.should
|
118
|
+
counter.should == 0
|
119
119
|
|
120
120
|
sleep 2.5
|
121
|
-
counter.should
|
121
|
+
counter.should == 2
|
122
122
|
end
|
123
123
|
|
124
|
-
#it '
|
124
|
+
#it 'honours :dont_reschedule' do
|
125
125
|
# stack = []
|
126
126
|
# @s.every 0.400 do |job|
|
127
127
|
# if stack.size > 3
|
@@ -136,7 +136,7 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
136
136
|
# stack.should.equal(%w[ ok ok ok ok done ])
|
137
137
|
#end
|
138
138
|
|
139
|
-
it '
|
139
|
+
it 'accepts job.unschedule within the job' do
|
140
140
|
|
141
141
|
stack = []
|
142
142
|
|
@@ -151,11 +151,11 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
151
151
|
|
152
152
|
sleep 4
|
153
153
|
|
154
|
-
@s.jobs.size.should
|
155
|
-
stack.should
|
154
|
+
@s.jobs.size.should == 0
|
155
|
+
stack.should == %w[ ok ok ok ok done ]
|
156
156
|
end
|
157
157
|
|
158
|
-
it '
|
158
|
+
it 'respects :blocking => true' do
|
159
159
|
|
160
160
|
stack = []
|
161
161
|
|
@@ -166,28 +166,66 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
166
166
|
|
167
167
|
sleep 5
|
168
168
|
|
169
|
-
stack.should
|
169
|
+
stack.should == %w[ ok ok ]
|
170
170
|
end
|
171
171
|
|
172
|
+
it 'lists the "trigger threads"' do
|
173
|
+
|
174
|
+
@s.every '1s' do
|
175
|
+
sleep 10
|
176
|
+
end
|
177
|
+
sleep 5
|
178
|
+
|
179
|
+
@s.trigger_threads.size.should == 4
|
180
|
+
end
|
172
181
|
end
|
173
182
|
|
174
183
|
describe Rufus::Scheduler::EveryJob do
|
175
184
|
|
176
|
-
before do
|
185
|
+
before(:each) do
|
177
186
|
@s = start_scheduler
|
178
187
|
end
|
179
|
-
after do
|
188
|
+
after(:each) do
|
180
189
|
stop_scheduler(@s)
|
181
190
|
end
|
182
191
|
|
183
|
-
it '
|
192
|
+
it 'responds to #next_time' do
|
184
193
|
|
185
194
|
t = Time.now + 3 * 3600
|
186
195
|
|
187
196
|
job = @s.every '3h' do
|
188
197
|
end
|
189
198
|
|
190
|
-
job.next_time.to_i.should
|
199
|
+
job.next_time.to_i.should == t.to_i
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
it 'does not allow a job to overlap execution if set !allow_overlapping' do
|
204
|
+
|
205
|
+
stack = []
|
206
|
+
|
207
|
+
@s.every '1s', :allow_overlapping => false do |job|
|
208
|
+
stack << 'ok'
|
209
|
+
sleep 2
|
210
|
+
end
|
211
|
+
|
212
|
+
sleep 5
|
213
|
+
|
214
|
+
stack.size.should == 2
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'allows a job to overlap execution (backward compatibility?)' do
|
218
|
+
|
219
|
+
stack = []
|
220
|
+
|
221
|
+
@s.every '1s' do |job|
|
222
|
+
stack << 'ok'
|
223
|
+
sleep 2
|
224
|
+
end
|
225
|
+
|
226
|
+
sleep 5
|
227
|
+
|
228
|
+
stack.size.should == 4
|
191
229
|
end
|
192
230
|
end
|
193
231
|
|