rufus-scheduler 2.0.24 → 3.0.0
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/CHANGELOG.txt +6 -0
- data/CREDITS.txt +4 -0
- data/README.md +1064 -0
- data/Rakefile +1 -4
- data/TODO.txt +145 -55
- data/lib/rufus/scheduler.rb +502 -26
- data/lib/rufus/{sc → scheduler}/cronline.rb +46 -17
- data/lib/rufus/{sc/version.rb → scheduler/job_array.rb} +56 -4
- data/lib/rufus/scheduler/jobs.rb +548 -0
- data/lib/rufus/scheduler/util.rb +318 -0
- data/rufus-scheduler.gemspec +30 -4
- data/spec/cronline_spec.rb +29 -8
- data/spec/error_spec.rb +116 -0
- data/spec/job_array_spec.rb +39 -0
- data/spec/job_at_spec.rb +58 -0
- data/spec/job_cron_spec.rb +67 -0
- data/spec/job_every_spec.rb +71 -0
- data/spec/job_in_spec.rb +20 -0
- data/spec/job_interval_spec.rb +68 -0
- data/spec/job_repeat_spec.rb +308 -0
- data/spec/job_spec.rb +387 -115
- data/spec/lockfile_spec.rb +61 -0
- data/spec/parse_spec.rb +203 -0
- data/spec/schedule_at_spec.rb +129 -0
- data/spec/schedule_cron_spec.rb +66 -0
- data/spec/schedule_every_spec.rb +109 -0
- data/spec/schedule_in_spec.rb +80 -0
- data/spec/schedule_interval_spec.rb +128 -0
- data/spec/scheduler_spec.rb +831 -124
- data/spec/spec_helper.rb +65 -0
- data/spec/threads_spec.rb +75 -0
- metadata +64 -59
- data/README.rdoc +0 -661
- data/lib/rufus/otime.rb +0 -3
- data/lib/rufus/sc/jobqueues.rb +0 -160
- data/lib/rufus/sc/jobs.rb +0 -471
- data/lib/rufus/sc/rtime.rb +0 -363
- data/lib/rufus/sc/scheduler.rb +0 -636
- data/spec/at_in_spec.rb +0 -47
- data/spec/at_spec.rb +0 -125
- data/spec/blocking_spec.rb +0 -64
- data/spec/cron_spec.rb +0 -134
- data/spec/every_spec.rb +0 -304
- data/spec/exception_spec.rb +0 -113
- data/spec/in_spec.rb +0 -150
- data/spec/mutex_spec.rb +0 -159
- data/spec/rtime_spec.rb +0 -137
- data/spec/schedulable_spec.rb +0 -97
- data/spec/spec_base.rb +0 -87
- data/spec/stress_schedule_unschedule_spec.rb +0 -159
- data/spec/timeout_spec.rb +0 -148
- data/test/kjw.rb +0 -113
- data/test/t.rb +0 -20
@@ -0,0 +1,308 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Wed Apr 17 06:00:59 JST 2013
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'spec_helper'
|
9
|
+
|
10
|
+
|
11
|
+
describe Rufus::Scheduler::RepeatJob do
|
12
|
+
|
13
|
+
before :each do
|
14
|
+
@scheduler = Rufus::Scheduler.new
|
15
|
+
end
|
16
|
+
after :each do
|
17
|
+
@scheduler.shutdown
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#pause' do
|
21
|
+
|
22
|
+
it 'pauses the job' do
|
23
|
+
|
24
|
+
counter = 0
|
25
|
+
|
26
|
+
job =
|
27
|
+
@scheduler.schedule_every('0.5s') do
|
28
|
+
counter += 1
|
29
|
+
end
|
30
|
+
|
31
|
+
counter.should == 0
|
32
|
+
|
33
|
+
while counter < 1; sleep(0.1); end
|
34
|
+
|
35
|
+
job.pause
|
36
|
+
|
37
|
+
sleep(1)
|
38
|
+
|
39
|
+
counter.should == 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#paused?' do
|
44
|
+
|
45
|
+
it 'returns true if the job is paused' do
|
46
|
+
|
47
|
+
job = @scheduler.schedule_every('10s') do; end
|
48
|
+
|
49
|
+
job.pause
|
50
|
+
|
51
|
+
job.paused?.should == true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns false if the job is not paused' do
|
55
|
+
|
56
|
+
job = @scheduler.schedule_every('10s') do; end
|
57
|
+
|
58
|
+
job.paused?.should == false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#resume' do
|
63
|
+
|
64
|
+
it 'resumes a paused job' do
|
65
|
+
|
66
|
+
counter = 0
|
67
|
+
|
68
|
+
job =
|
69
|
+
@scheduler.schedule_every('0.5s') do
|
70
|
+
counter += 1
|
71
|
+
end
|
72
|
+
|
73
|
+
job.pause
|
74
|
+
job.resume
|
75
|
+
|
76
|
+
sleep(1.5)
|
77
|
+
|
78
|
+
counter.should > 1
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'has no effect on a not paused job' do
|
82
|
+
|
83
|
+
job = @scheduler.schedule_every('10s') do; end
|
84
|
+
|
85
|
+
job.resume
|
86
|
+
|
87
|
+
job.paused?.should == false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe ':times => i' do
|
92
|
+
|
93
|
+
it 'lets a job unschedule itself after i times' do
|
94
|
+
|
95
|
+
counter = 0
|
96
|
+
|
97
|
+
job =
|
98
|
+
@scheduler.schedule_every '0.5s', :times => 3 do
|
99
|
+
counter = counter + 1
|
100
|
+
end
|
101
|
+
|
102
|
+
sleep(2.6)
|
103
|
+
|
104
|
+
counter.should == 3
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'is OK when passed a nil instead of an integer' do
|
108
|
+
|
109
|
+
counter = 0
|
110
|
+
|
111
|
+
job =
|
112
|
+
@scheduler.schedule_every '0.5s', :times => nil do
|
113
|
+
counter = counter + 1
|
114
|
+
end
|
115
|
+
|
116
|
+
sleep(2.5)
|
117
|
+
|
118
|
+
counter.should > 3
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'raises when passed something else than nil or an integer' do
|
122
|
+
|
123
|
+
lambda {
|
124
|
+
@scheduler.schedule_every '0.5s', :times => 'nada' do; end
|
125
|
+
}.should raise_error(ArgumentError)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe ':first/:first_in/:first_at => point in time' do
|
130
|
+
|
131
|
+
it 'accepts a Time instance' do
|
132
|
+
|
133
|
+
t = Time.now + 10
|
134
|
+
|
135
|
+
job = @scheduler.schedule_every '0.5s', :first => t do; end
|
136
|
+
|
137
|
+
job.first_at.should == t
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'accepts a time string' do
|
141
|
+
|
142
|
+
t = Time.now + 10
|
143
|
+
|
144
|
+
job = @scheduler.schedule_every '0.5s', :first => t.to_s do; end
|
145
|
+
|
146
|
+
job.first_at.to_s.should == t.to_s
|
147
|
+
job.first_at.zone.should == t.zone
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'only lets the job trigger after the :first' do
|
151
|
+
|
152
|
+
t = Time.now + 1.4
|
153
|
+
counter = 0
|
154
|
+
|
155
|
+
job =
|
156
|
+
@scheduler.schedule_every '0.5s', :first => t do
|
157
|
+
counter = counter + 1
|
158
|
+
end
|
159
|
+
|
160
|
+
sleep(1)
|
161
|
+
|
162
|
+
counter.should == 0
|
163
|
+
|
164
|
+
sleep(1)
|
165
|
+
|
166
|
+
counter.should > 0
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'raises on points in the past' do
|
170
|
+
|
171
|
+
lambda {
|
172
|
+
|
173
|
+
@scheduler.schedule_every '0.5s', :first => Time.now - 60 do; end
|
174
|
+
|
175
|
+
}.should raise_error(ArgumentError)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe ':first/:first_in/:first_at => duration' do
|
180
|
+
|
181
|
+
it 'accepts a duration string' do
|
182
|
+
|
183
|
+
t = Time.now
|
184
|
+
|
185
|
+
job = @scheduler.schedule_every '0.5s', :first => '1h' do; end
|
186
|
+
|
187
|
+
job.first_at.should >= t + 3600
|
188
|
+
job.first_at.should < t + 3601
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'accepts a duration in seconds (integer)' do
|
192
|
+
|
193
|
+
t = Time.now
|
194
|
+
|
195
|
+
job = @scheduler.schedule_every '0.5s', :first => 3600 do; end
|
196
|
+
|
197
|
+
job.first_at.should >= t + 3600
|
198
|
+
job.first_at.should < t + 3601
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'raises if the argument cannot be used' do
|
202
|
+
|
203
|
+
lambda {
|
204
|
+
@scheduler.every '0.5s', :first => :nada do; end
|
205
|
+
}.should raise_error(ArgumentError)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
describe '#first_at=' do
|
210
|
+
|
211
|
+
it 'can be used to set first_at directly' do
|
212
|
+
|
213
|
+
job = @scheduler.schedule_every '0.5s', :first => 3600 do; end
|
214
|
+
job.first_at = '2030-12-12 12:00:30'
|
215
|
+
|
216
|
+
job.first_at.strftime('%c').should == 'Thu Dec 12 12:00:30 2030'
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe ':last/:last_in/:last_at => point in time' do
|
221
|
+
|
222
|
+
it 'accepts a Time instance' do
|
223
|
+
|
224
|
+
t = Time.now + 10
|
225
|
+
|
226
|
+
job = @scheduler.schedule_every '0.5s', :last => t do; end
|
227
|
+
|
228
|
+
job.last_at.should == t
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'unschedules the job after the last_at time' do
|
232
|
+
|
233
|
+
t = Time.now + 2
|
234
|
+
counter = 0
|
235
|
+
|
236
|
+
job =
|
237
|
+
@scheduler.schedule_every '0.5s', :last => t do
|
238
|
+
counter = counter + 1
|
239
|
+
end
|
240
|
+
|
241
|
+
sleep 3
|
242
|
+
|
243
|
+
counter.should == 3
|
244
|
+
@scheduler.jobs.should_not include(job)
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'accepts a time string' do
|
248
|
+
|
249
|
+
t = Time.now + 10
|
250
|
+
|
251
|
+
job = @scheduler.schedule_every '0.5s', :last => t.to_s do; end
|
252
|
+
|
253
|
+
job.last_at.to_s.should == t.to_s
|
254
|
+
job.last_at.zone.should == t.zone
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'raises on a point in the past' do
|
258
|
+
|
259
|
+
lambda {
|
260
|
+
|
261
|
+
@scheduler.every '0.5s', :last => Time.now - 60 do; end
|
262
|
+
|
263
|
+
}.should raise_error(ArgumentError)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe ':last/:last_in/:last_at => duration' do
|
268
|
+
|
269
|
+
it 'accepts a duration string' do
|
270
|
+
|
271
|
+
t = Time.now
|
272
|
+
|
273
|
+
job = @scheduler.schedule_every '0.5s', :last_in => '2s' do; end
|
274
|
+
|
275
|
+
job.last_at.should >= t + 2
|
276
|
+
job.last_at.should < t + 2.5
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'accepts a duration in seconds (integer)' do
|
280
|
+
|
281
|
+
t = Time.now
|
282
|
+
|
283
|
+
job = @scheduler.schedule_every '0.5s', :last_in => 2.0 do; end
|
284
|
+
|
285
|
+
job.last_at.should >= t + 2
|
286
|
+
job.last_at.should < t + 2.5
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'raises if the argument is worthless' do
|
290
|
+
|
291
|
+
lambda {
|
292
|
+
@scheduler.every '0.5s', :last => :nada do; end
|
293
|
+
}.should raise_error(ArgumentError)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
describe '#last_at=' do
|
298
|
+
|
299
|
+
it 'can be used to set last_at directly' do
|
300
|
+
|
301
|
+
job = @scheduler.schedule_every '0.5s', :last_in => 10.0 do; end
|
302
|
+
job.last_at = '2030-12-12 12:00:30'
|
303
|
+
|
304
|
+
job.last_at.strftime('%c').should == 'Thu Dec 12 12:00:30 2030'
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
data/spec/job_spec.rb
CHANGED
@@ -2,240 +2,512 @@
|
|
2
2
|
#
|
3
3
|
# Specifying rufus-scheduler
|
4
4
|
#
|
5
|
-
# Wed Apr
|
5
|
+
# Wed Apr 17 06:00:59 JST 2013
|
6
6
|
#
|
7
7
|
|
8
|
-
require '
|
8
|
+
require 'spec_helper'
|
9
9
|
|
10
10
|
|
11
|
-
describe
|
11
|
+
describe Rufus::Scheduler::Job do
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
# specify behaviours common to all job classes
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
|
17
|
+
@taoe = Thread.abort_on_exception
|
18
|
+
Thread.abort_on_exception = false
|
19
|
+
|
20
|
+
@ose = $stderr
|
21
|
+
$stderr = StringIO.new
|
22
|
+
|
23
|
+
@scheduler = Rufus::Scheduler.new
|
15
24
|
end
|
16
|
-
|
17
|
-
|
25
|
+
|
26
|
+
after :each do
|
27
|
+
|
28
|
+
@scheduler.shutdown
|
29
|
+
|
30
|
+
Thread.abort_on_exception = @taoe
|
31
|
+
|
32
|
+
$stderr = @ose
|
18
33
|
end
|
19
34
|
|
20
|
-
describe
|
35
|
+
describe '#last_time' do
|
21
36
|
|
22
|
-
|
37
|
+
it 'returns nil if the job never fired' do
|
23
38
|
|
24
|
-
|
39
|
+
job = @scheduler.schedule_in '10d' do; end
|
25
40
|
|
26
|
-
|
27
|
-
|
41
|
+
job.last_time.should == nil
|
42
|
+
end
|
28
43
|
|
29
|
-
|
30
|
-
end
|
44
|
+
it 'returns the last time the job fired' do
|
31
45
|
|
32
|
-
|
46
|
+
job = @scheduler.schedule_in '0s' do; end
|
33
47
|
|
34
|
-
|
35
|
-
sleep(100)
|
36
|
-
end
|
48
|
+
sleep 0.4
|
37
49
|
|
38
|
-
|
50
|
+
job.last_time.should_not == nil
|
51
|
+
end
|
52
|
+
end
|
39
53
|
|
40
|
-
|
41
|
-
end
|
54
|
+
describe '#threads' do
|
42
55
|
|
43
|
-
|
56
|
+
it 'returns an empty list when the job is not running' do
|
44
57
|
|
45
|
-
|
58
|
+
job = @scheduler.in('1d', :job => true) {}
|
46
59
|
|
47
|
-
|
48
|
-
|
49
|
-
$exception = e
|
50
|
-
end
|
60
|
+
job.threads.size.should == 0
|
61
|
+
end
|
51
62
|
|
52
|
-
|
53
|
-
|
63
|
+
it 'returns an empty list after the job terminated' do
|
64
|
+
|
65
|
+
job = @scheduler.in('0s', :job => true) {}
|
66
|
+
|
67
|
+
sleep 0.8
|
68
|
+
|
69
|
+
job.threads.size.should == 0
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'lists the threads the job currently runs in' do
|
73
|
+
|
74
|
+
job =
|
75
|
+
@scheduler.schedule_in('0s') do
|
76
|
+
sleep(1)
|
54
77
|
end
|
55
78
|
|
56
|
-
|
79
|
+
sleep 0.4
|
57
80
|
|
58
|
-
|
59
|
-
|
60
|
-
|
81
|
+
job.threads.size.should == 1
|
82
|
+
|
83
|
+
t = job.threads.first
|
84
|
+
t[:rufus_scheduler_job].should == job
|
61
85
|
end
|
86
|
+
end
|
62
87
|
|
63
|
-
|
88
|
+
describe '#kill' do
|
64
89
|
|
65
|
-
|
90
|
+
it 'has no effect if the job is not running' do
|
66
91
|
|
67
|
-
|
68
|
-
|
92
|
+
job = @scheduler.schedule_in '10d' do; end
|
93
|
+
|
94
|
+
tls = Thread.list.size
|
95
|
+
|
96
|
+
job.kill
|
97
|
+
|
98
|
+
Thread.list.size.should == tls
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'makes the threads vacant' do
|
102
|
+
|
103
|
+
counter = 0
|
104
|
+
|
105
|
+
job =
|
106
|
+
@scheduler.schedule_in '0s' do
|
107
|
+
sleep 2
|
108
|
+
counter = counter + 1
|
69
109
|
end
|
70
110
|
|
71
|
-
|
111
|
+
sleep 1
|
72
112
|
|
73
|
-
|
74
|
-
|
113
|
+
v0 = @scheduler.work_threads(:vacant).size
|
114
|
+
a0 = @scheduler.work_threads(:active).size
|
115
|
+
|
116
|
+
job.kill
|
117
|
+
|
118
|
+
sleep 2
|
119
|
+
|
120
|
+
v1 = @scheduler.work_threads(:vacant).size
|
121
|
+
a1 = @scheduler.work_threads(:active).size
|
122
|
+
|
123
|
+
counter.should == 0
|
124
|
+
|
125
|
+
v0.should == 0
|
126
|
+
a0.should == 1
|
127
|
+
|
128
|
+
v1.should == 1
|
129
|
+
a1.should == 0
|
75
130
|
end
|
76
131
|
end
|
77
132
|
|
78
|
-
describe
|
133
|
+
describe '#running?' do
|
79
134
|
|
80
|
-
|
135
|
+
it 'returns false when the job is not running in any thread' do
|
81
136
|
|
82
|
-
|
137
|
+
job = @scheduler.in('1d', :job => true) {}
|
83
138
|
|
84
|
-
|
85
|
-
|
139
|
+
job.running?.should == false
|
140
|
+
end
|
86
141
|
|
87
|
-
|
142
|
+
it 'returns true when the job is running in at least one thread' do
|
88
143
|
|
89
|
-
|
144
|
+
job = @scheduler.in('0s', :job => true) { sleep(1) }
|
90
145
|
|
91
|
-
|
92
|
-
|
146
|
+
sleep 0.4
|
147
|
+
|
148
|
+
job.running?.should == true
|
93
149
|
end
|
150
|
+
end
|
94
151
|
|
95
|
-
|
152
|
+
describe '#scheduled?' do
|
96
153
|
|
97
|
-
|
154
|
+
it 'returns true when the job is scheduled' do
|
98
155
|
|
99
|
-
|
156
|
+
job = @scheduler.schedule_in('1d') {}
|
100
157
|
|
101
|
-
|
102
|
-
|
158
|
+
job.scheduled?.should == true
|
159
|
+
end
|
103
160
|
|
104
|
-
|
105
|
-
|
106
|
-
|
161
|
+
it 'returns false when the job is not scheduled' do
|
162
|
+
|
163
|
+
job = @scheduler.schedule_in('0.1s') {}
|
164
|
+
|
165
|
+
sleep 0.4
|
166
|
+
|
167
|
+
job.scheduled?.should == false
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'returns true for repeat jobs that are running' do
|
171
|
+
|
172
|
+
job = @scheduler.schedule_interval('0.4s') { sleep(10) }
|
173
|
+
|
174
|
+
sleep 1
|
175
|
+
|
176
|
+
job.running?.should == true
|
177
|
+
job.scheduled?.should == true
|
107
178
|
end
|
108
179
|
end
|
109
180
|
|
110
|
-
|
181
|
+
context 'job-local variables' do
|
111
182
|
|
112
|
-
describe '#
|
183
|
+
describe '#[]=' do
|
113
184
|
|
114
|
-
it '
|
185
|
+
it 'sets a job-local variable' do
|
115
186
|
|
116
|
-
job =
|
117
|
-
|
187
|
+
job =
|
188
|
+
@scheduler.schedule_every '1s' do |job|
|
189
|
+
job[:counter] ||= 0
|
190
|
+
job[:counter] += 1
|
191
|
+
end
|
192
|
+
|
193
|
+
sleep 3
|
118
194
|
|
119
|
-
|
195
|
+
job[:counter].should > 1
|
196
|
+
end
|
197
|
+
end
|
120
198
|
|
121
|
-
|
199
|
+
describe '#[]' do
|
122
200
|
|
123
|
-
|
201
|
+
it 'returns nil if there is no such entry' do
|
202
|
+
|
203
|
+
job = @scheduler.schedule_in '1s' do; end
|
204
|
+
|
205
|
+
job[:nada].should == nil
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'returns the value of a job-local variable' do
|
209
|
+
|
210
|
+
job = @scheduler.schedule_in '1s' do; end
|
211
|
+
job[:x] = :y
|
212
|
+
|
213
|
+
job[:x].should == :y
|
124
214
|
end
|
125
215
|
end
|
126
216
|
|
127
|
-
describe '#
|
217
|
+
describe '#key?' do
|
128
218
|
|
129
|
-
it 'returns
|
219
|
+
it 'returns true if there is an entry with the given key' do
|
130
220
|
|
131
|
-
|
221
|
+
job = @scheduler.schedule_in '1s' do; end
|
222
|
+
job[:x] = :y
|
132
223
|
|
133
|
-
job
|
134
|
-
|
224
|
+
job.key?(:x).should == true
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe '#keys' do
|
229
|
+
|
230
|
+
it 'returns the array of keys of the job-local variables' do
|
135
231
|
|
136
|
-
job.
|
137
|
-
job
|
232
|
+
job = @scheduler.schedule_in '1s' do; end
|
233
|
+
job[:x] = :y
|
234
|
+
job['hello'] = :z
|
235
|
+
job[123] = {}
|
236
|
+
|
237
|
+
job.keys.sort_by { |k| k.to_s }.should == [ 123, 'hello', :x ]
|
138
238
|
end
|
139
239
|
end
|
140
240
|
end
|
141
241
|
|
142
|
-
|
242
|
+
context ':tag / :tags => [ t0, t1 ]' do
|
143
243
|
|
144
|
-
|
244
|
+
it 'accepts one tag' do
|
145
245
|
|
146
|
-
|
246
|
+
job = @scheduler.in '10d', :job => true, :tag => 't0' do; end
|
147
247
|
|
148
|
-
|
248
|
+
job.tags.should == %w[ t0 ]
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'accepts an array of tags' do
|
252
|
+
|
253
|
+
job = @scheduler.in '10d', :job => true, :tag => %w[ t0 t1 ] do; end
|
254
|
+
|
255
|
+
job.tags.should == %w[ t0 t1 ]
|
256
|
+
end
|
149
257
|
|
150
|
-
|
258
|
+
it 'turns tags into strings' do
|
259
|
+
|
260
|
+
job = @scheduler.in '10d', :job => true, :tags => [ 1, 2 ] do; end
|
261
|
+
|
262
|
+
job.tags.should == %w[ 1 2 ]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
context ':blocking => true' do
|
267
|
+
|
268
|
+
it 'runs the job in the same thread as the scheduler thread' do
|
269
|
+
|
270
|
+
job =
|
271
|
+
@scheduler.in('0s', :job => true, :blocking => true) do
|
272
|
+
sleep(1)
|
151
273
|
end
|
152
274
|
|
153
|
-
|
154
|
-
|
155
|
-
|
275
|
+
sleep 0.4
|
276
|
+
|
277
|
+
job.threads.first.should == @scheduler.thread
|
278
|
+
|
279
|
+
sleep 1.4
|
280
|
+
|
281
|
+
job.threads.size.should == 0
|
156
282
|
end
|
283
|
+
end
|
157
284
|
|
158
|
-
|
285
|
+
context 'default one thread per job behaviour' do
|
159
286
|
|
160
|
-
|
287
|
+
it 'runs the job in a dedicated thread' do
|
161
288
|
|
162
|
-
|
289
|
+
job =
|
290
|
+
@scheduler.in('0s', :job => true) do
|
291
|
+
sleep(1)
|
292
|
+
end
|
163
293
|
|
164
|
-
|
165
|
-
|
294
|
+
sleep 0.4
|
295
|
+
|
296
|
+
job.threads.first.should_not == @scheduler.thread
|
297
|
+
|
298
|
+
sleep 1.4
|
299
|
+
|
300
|
+
job.threads.size.should == 0
|
166
301
|
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context ':allow_overlapping / :allow_overlap / :overlap' do
|
167
305
|
|
168
|
-
|
306
|
+
context 'default (:overlap => true)' do
|
169
307
|
|
170
|
-
it '
|
308
|
+
it 'lets a job overlap itself' do
|
171
309
|
|
172
|
-
job =
|
310
|
+
job =
|
311
|
+
@scheduler.every('0.3', :job => true) do
|
312
|
+
sleep(5)
|
313
|
+
end
|
173
314
|
|
174
|
-
|
315
|
+
sleep 3
|
175
316
|
|
176
|
-
job.
|
317
|
+
job.threads.size.should > 1
|
177
318
|
end
|
178
319
|
end
|
179
320
|
|
180
|
-
|
321
|
+
context 'when :overlap => false' do
|
181
322
|
|
182
|
-
it '
|
323
|
+
it 'prevents a job from overlapping itself' do
|
183
324
|
|
184
|
-
job =
|
325
|
+
job =
|
326
|
+
@scheduler.every('0.3', :job => true, :overlap => false) do
|
327
|
+
sleep(5)
|
328
|
+
end
|
185
329
|
|
186
|
-
|
330
|
+
sleep 3
|
187
331
|
|
188
|
-
job.
|
332
|
+
job.threads.size.should == 1
|
189
333
|
end
|
190
334
|
end
|
191
335
|
end
|
192
336
|
|
193
|
-
|
337
|
+
context ':mutex' do
|
338
|
+
|
339
|
+
context ':mutex => "mutex_name"' do
|
340
|
+
|
341
|
+
it 'prevents concurrent executions' do
|
342
|
+
|
343
|
+
j0 =
|
344
|
+
@scheduler.in('0s', :job => true, :mutex => 'vladivostok') do
|
345
|
+
sleep(3)
|
346
|
+
end
|
347
|
+
j1 =
|
348
|
+
@scheduler.in('0s', :job => true, :mutex => 'vladivostok') do
|
349
|
+
sleep(3)
|
350
|
+
end
|
351
|
+
|
352
|
+
sleep 0.7
|
353
|
+
|
354
|
+
if j0.threads.any?
|
355
|
+
j0.threads.size.should == 1
|
356
|
+
j1.threads.size.should == 0
|
357
|
+
else
|
358
|
+
j0.threads.size.should == 0
|
359
|
+
j1.threads.size.should == 1
|
360
|
+
end
|
361
|
+
|
362
|
+
@scheduler.mutexes.keys.should == %w[ vladivostok ]
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
context ':mutex => mutex_instance' do
|
367
|
+
|
368
|
+
it 'prevents concurrent executions' do
|
194
369
|
|
195
|
-
|
370
|
+
m = Mutex.new
|
196
371
|
|
197
|
-
|
372
|
+
j0 = @scheduler.in('0s', :job => true, :mutex => m) { sleep(3) }
|
373
|
+
j1 = @scheduler.in('0s', :job => true, :mutex => m) { sleep(3) }
|
198
374
|
|
199
|
-
|
375
|
+
sleep 0.7
|
376
|
+
|
377
|
+
if j0.threads.any?
|
378
|
+
j0.threads.size.should == 1
|
379
|
+
j1.threads.size.should == 0
|
380
|
+
else
|
381
|
+
j0.threads.size.should == 0
|
382
|
+
j1.threads.size.should == 1
|
200
383
|
end
|
201
384
|
|
202
|
-
|
203
|
-
(job.next_time.to_i - Time.now.to_i).should satisfy { |v| v < 60 }
|
385
|
+
@scheduler.mutexes.keys.should == []
|
204
386
|
end
|
205
387
|
end
|
206
388
|
|
207
|
-
|
389
|
+
context ':mutex => [ array_of_mutex_names_or_instances ]' do
|
390
|
+
|
391
|
+
it 'prevents concurrent executions' do
|
208
392
|
|
209
|
-
|
393
|
+
j0 =
|
394
|
+
@scheduler.in('0s', :job => true, :mutex => %w[ a b ]) do
|
395
|
+
sleep(3)
|
396
|
+
end
|
397
|
+
j1 =
|
398
|
+
@scheduler.in('0s', :job => true, :mutex => %w[ a b ]) do
|
399
|
+
sleep(3)
|
400
|
+
end
|
210
401
|
|
211
|
-
|
402
|
+
sleep 0.7
|
403
|
+
|
404
|
+
if j0.threads.any?
|
405
|
+
j0.threads.size.should == 1
|
406
|
+
j1.threads.size.should == 0
|
407
|
+
else
|
408
|
+
j0.threads.size.should == 0
|
409
|
+
j1.threads.size.should == 1
|
410
|
+
end
|
212
411
|
|
213
|
-
|
412
|
+
@scheduler.mutexes.keys.sort.should == %w[ a b ]
|
214
413
|
end
|
215
414
|
end
|
415
|
+
end
|
416
|
+
|
417
|
+
context ':timeout => duration_or_point_in_time' do
|
418
|
+
|
419
|
+
it 'interrupts the job it is stashed to (duration)' do
|
420
|
+
|
421
|
+
counter = 0
|
422
|
+
toe = nil
|
423
|
+
|
424
|
+
job =
|
425
|
+
@scheduler.schedule_in '0s', :timeout => '1s' do
|
426
|
+
begin
|
427
|
+
counter = counter + 1
|
428
|
+
sleep 1.5
|
429
|
+
counter = counter + 1
|
430
|
+
rescue Rufus::Scheduler::TimeoutError => e
|
431
|
+
toe = e
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
sleep(3)
|
436
|
+
|
437
|
+
counter.should == 1
|
438
|
+
toe.class.should == Rufus::Scheduler::TimeoutError
|
439
|
+
end
|
440
|
+
|
441
|
+
it 'interrupts the job it is stashed to (point in time)' do
|
216
442
|
|
217
|
-
|
443
|
+
counter = 0
|
218
444
|
|
219
|
-
|
445
|
+
job =
|
446
|
+
@scheduler.schedule_in '0s', :timeout => Time.now + 1 do
|
447
|
+
begin
|
448
|
+
counter = counter + 1
|
449
|
+
sleep 1.5
|
450
|
+
counter = counter + 1
|
451
|
+
rescue Rufus::Scheduler::TimeoutError => e
|
452
|
+
end
|
453
|
+
end
|
220
454
|
|
221
|
-
|
455
|
+
sleep(3)
|
456
|
+
|
457
|
+
counter.should == 1
|
458
|
+
end
|
222
459
|
|
223
|
-
|
460
|
+
it 'starts timing when the job enters successfully all its mutexes' do
|
224
461
|
|
225
|
-
|
462
|
+
t0, t1, t2 = nil
|
463
|
+
|
464
|
+
@scheduler.schedule_in '0s', :mutex => 'a' do
|
465
|
+
sleep 1
|
466
|
+
t0 = Time.now
|
226
467
|
end
|
468
|
+
|
469
|
+
job =
|
470
|
+
@scheduler.schedule_in '0.5s', :mutex => 'a', :timeout => '1s' do
|
471
|
+
begin
|
472
|
+
t1 = Time.now
|
473
|
+
sleep 2
|
474
|
+
rescue Rufus::Scheduler::TimeoutError => e
|
475
|
+
t2 = Time.now
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
sleep 3
|
480
|
+
|
481
|
+
t0.should <= t1
|
482
|
+
|
483
|
+
d = t2 - t1
|
484
|
+
d.should >= 1.0
|
485
|
+
d.should < 1.5
|
227
486
|
end
|
228
487
|
|
229
|
-
|
488
|
+
it 'emits the timeout information to $stderr (default #on_error)' do
|
489
|
+
|
490
|
+
@scheduler.every('1s', :timeout => '0.5s') do
|
491
|
+
sleep 0.9
|
492
|
+
end
|
493
|
+
|
494
|
+
sleep 2
|
230
495
|
|
231
|
-
|
496
|
+
$stderr.string.should match(/Rufus::Scheduler::TimeoutError/)
|
497
|
+
end
|
232
498
|
|
233
|
-
|
499
|
+
it 'does not prevent a repeat job from recurring' do
|
234
500
|
|
235
|
-
|
501
|
+
counter = 0
|
236
502
|
|
237
|
-
|
503
|
+
@scheduler.every('1s', :timeout => '0.5s') do
|
504
|
+
counter = counter + 1
|
505
|
+
sleep 0.9
|
238
506
|
end
|
507
|
+
|
508
|
+
sleep 3
|
509
|
+
|
510
|
+
counter.should > 1
|
239
511
|
end
|
240
512
|
end
|
241
513
|
end
|