rufus-scheduler 2.0.19 → 2.0.20
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +9 -0
- data/CREDITS.txt +4 -0
- data/README.rdoc +48 -7
- data/lib/rufus/sc/cronline.rb +96 -73
- data/lib/rufus/sc/jobs.rb +1 -1
- data/lib/rufus/sc/rtime.rb +0 -2
- data/lib/rufus/sc/scheduler.rb +59 -1
- data/lib/rufus/sc/version.rb +1 -1
- data/lib/rufus/scheduler.rb +7 -0
- data/spec/cronline_spec.rb +78 -31
- data/spec/exception_spec.rb +17 -1
- data/spec/rtime_spec.rb +1 -1
- data/spec/scheduler_spec.rb +32 -0
- data/spec/spec_base.rb +9 -0
- metadata +25 -32
- data/out.txt +0 -4
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
+
== rufus-scheduler - 2.0.20 released 2013/07/15
|
6
|
+
|
7
|
+
- add Rufus::Scheduler.new (so that rs 3.0 quickstarts are OK with 2.0.20)
|
8
|
+
- implement CronLine#previous_time(now=Time.now) (Idea Matteo Cerutti)
|
9
|
+
- throw ArgumentError for invalid cron lines (Thanks Aimee Rose)
|
10
|
+
- cron 0 vs 24 hour case straightening (Thanks Aimee Rose)
|
11
|
+
- support for sun#L or sun#-2 in cron lines
|
12
|
+
|
13
|
+
|
5
14
|
== rufus-scheduler - 2.0.19 released 2013/05/07
|
6
15
|
|
7
16
|
- raise ArgumentError on <= 0.0 "every" frequency (Thanks Lucy Fu)
|
data/CREDITS.txt
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
|
5
5
|
== Contributors
|
6
6
|
|
7
|
+
- Thomas Sevestre (https://github.com/thomassevestre) :exception option
|
8
|
+
- Matteo Cerutti - last_time / previous_time idea (and initial implementation)
|
9
|
+
- Aimee Rose (https://github.com/AimeeRose) cronline and > 24
|
7
10
|
- Lucy Fu (https://github.com/lfu) arg error on <= 0 "every" freq
|
8
11
|
- Rainux Luo (https://github.com/rainux) multiple mutexes
|
9
12
|
- Andrew Davey (https://github.com/asdavey) "L" in cron lines
|
@@ -22,6 +25,7 @@
|
|
22
25
|
|
23
26
|
== Feedback
|
24
27
|
|
28
|
+
- Hongli Lai - Scheduler#stop(:terminate => true) request
|
25
29
|
- Tero Tilus - raises on unsupported/unknown options
|
26
30
|
- Louis Coilliot - Scheduler#running_jobs
|
27
31
|
- Henrique G. Testa - pause/resume concept
|
data/README.rdoc
CHANGED
@@ -98,12 +98,18 @@ The timezones are the ones supported by the 'tzinfo' rubygem (http://tzinfo.ruby
|
|
98
98
|
|
99
99
|
The timezone support was contributed by Tanzeeb Khalili.
|
100
100
|
|
101
|
-
|
101
|
+
"monthdays" are supported
|
102
102
|
|
103
103
|
scheduler.cron '0 22 * * sun#1,sun#2' do
|
104
104
|
# every first and second sunday of the month, at 22:00
|
105
105
|
end
|
106
106
|
|
107
|
+
It's also OK (since 2.0.19) to use L (for last monthday) or negative numbers.
|
108
|
+
|
109
|
+
scheduler.cron '0 22 * * sun#-1' do
|
110
|
+
# every last sunday of the month, at 22:00
|
111
|
+
end
|
112
|
+
|
107
113
|
|
108
114
|
== scheduler.join
|
109
115
|
|
@@ -132,6 +138,18 @@ You shouldn't be exposed to this issue when using EventMachine, since while runn
|
|
132
138
|
DO NOT CALL this #join method if you're running rufus-scheduler from Rails or Sinatra or any application that's already some kind of 'daemon'. It's not necessary! #join is meant for small standalone scripts.
|
133
139
|
|
134
140
|
|
141
|
+
== schedule.stop
|
142
|
+
|
143
|
+
scheduler.stop
|
144
|
+
|
145
|
+
This call stops the scheduler. It doesn't unschedule jobs. If there are running jobs, they're left running.
|
146
|
+
|
147
|
+
If you need to stop the scheduler and wait for all the jobs currently running to finish (without killing them), rufus-scheduler 2.0.20 brings a new :terminate => true option.
|
148
|
+
|
149
|
+
scheduler.stop(:terminate => true)
|
150
|
+
# returns once all the jobs have been unscheduled and no jobs is running
|
151
|
+
|
152
|
+
|
135
153
|
== block parameters
|
136
154
|
|
137
155
|
Scheduled blocks accept 0 or 1 parameter (this unique parameter is the job
|
@@ -319,7 +337,7 @@ The chronic gem may help (http://chronic.rubyforge.org/) :
|
|
319
337
|
require 'chronic' # sudo gem install chronic
|
320
338
|
|
321
339
|
scheduler.every '3h', :first_at => Chronic.parse('this tuesday 5:00') do
|
322
|
-
# do something starting this
|
340
|
+
# do something starting this tuesday
|
323
341
|
end
|
324
342
|
|
325
343
|
Note : setting a :first_at/:first_in in the past will get rufus-scheduler to trigger for all the past schedules until now. Adding :discard_past => true will prevent this.
|
@@ -520,6 +538,15 @@ For backward compatibility, overriding #log_exception is still OK :
|
|
520
538
|
|
521
539
|
Note that an every job or a cron job will stay scheduled even if it experiences an exception.
|
522
540
|
|
541
|
+
By default, all exceptions are rescued. It's easy to customize that behaviour :
|
542
|
+
|
543
|
+
scheduler = Rufus::Scheduler::PlainScheduler.start_new(:exception => StandardError)
|
544
|
+
# or
|
545
|
+
#scheduler = Rufus::Scheduler::EmScheduler.start_new(:exception => StandardError)
|
546
|
+
|
547
|
+
scheduler.in "3s" do
|
548
|
+
exit
|
549
|
+
end
|
523
550
|
|
524
551
|
== frequency
|
525
552
|
|
@@ -555,7 +582,7 @@ More and more ruby applications are using EventMachine. This flavour of the sche
|
|
555
582
|
|
556
583
|
== with Passenger
|
557
584
|
|
558
|
-
"it terminates for no apparent reason
|
585
|
+
"it terminates for no apparent reason!"
|
559
586
|
|
560
587
|
https://github.com/jmettraux/rufus-scheduler/issues/issue/10
|
561
588
|
|
@@ -576,22 +603,35 @@ The 'tzinfo' rubygem.
|
|
576
603
|
The ruby gem 'eventmachine' if you use Rufus::Scheduler::EmScheduler, else no other dependencies.
|
577
604
|
|
578
605
|
|
579
|
-
==
|
606
|
+
== support
|
607
|
+
|
608
|
+
If you identify and pinpoint a bug, please use the issue tracker. If you are unsure whether the fault lies in rufus-scheduler or in your software, use the mailing list. The mailing list is Google-powered, so, yes, you can search it.
|
609
|
+
|
610
|
+
Please read carefully: http://www.chiark.greenend.org.uk/~sgtatham/bugs.html (then re-read it).
|
611
|
+
|
612
|
+
|
613
|
+
=== mailing list
|
580
614
|
|
581
615
|
On the rufus-ruby list :
|
582
616
|
|
583
617
|
http://groups.google.com/group/rufus-ruby
|
584
618
|
|
619
|
+
Newcomers' first message is held for moderation in order to prevent spam. Further messages are not held.
|
620
|
+
|
621
|
+
|
622
|
+
=== issue tracker
|
585
623
|
|
586
|
-
|
624
|
+
https://github.com/jmettraux/rufus-scheduler/issues
|
587
625
|
|
588
|
-
http://rubyforge.org/tracker/?atid=18584&group_id=4812&func=browse
|
589
626
|
|
627
|
+
=== irc
|
590
628
|
|
591
|
-
|
629
|
+
If you come over to #ruote to ask for rufus-scheduler help, please make sure to 1) say hello 2) be polite 3) state that you're looking for rufus-scheduler help 4) remember that we cannot read your mind and guess whatever lies in your deployment.
|
592
630
|
|
593
631
|
irc.freenode.net #ruote
|
594
632
|
|
633
|
+
If there is no answer on IRC, use the mailing list.
|
634
|
+
|
595
635
|
|
596
636
|
== source
|
597
637
|
|
@@ -618,3 +658,4 @@ http://rufus.rubyforge.org
|
|
618
658
|
== license
|
619
659
|
|
620
660
|
MIT
|
661
|
+
|
data/lib/rufus/sc/cronline.rb
CHANGED
@@ -33,6 +33,9 @@ module Rufus
|
|
33
33
|
#
|
34
34
|
class CronLine
|
35
35
|
|
36
|
+
DAY_S = 24 * 3600
|
37
|
+
WEEK_S = 7 * DAY_S
|
38
|
+
|
36
39
|
# The string used for creating this cronline instance.
|
37
40
|
#
|
38
41
|
attr_reader :original
|
@@ -74,7 +77,7 @@ module Rufus
|
|
74
77
|
|
75
78
|
raise ArgumentError.new(
|
76
79
|
"invalid cronline: '#{line}'"
|
77
|
-
) if es && es.find { |e| ! e.is_a?(
|
80
|
+
) if es && es.find { |e| ! e.is_a?(Fixnum) }
|
78
81
|
end
|
79
82
|
end
|
80
83
|
|
@@ -125,25 +128,21 @@ module Rufus
|
|
125
128
|
time = @timezone ? @timezone.utc_to_local(now.getutc) : now
|
126
129
|
|
127
130
|
time = time - time.usec * 1e-6 + 1
|
128
|
-
#
|
131
|
+
# small adjustment before starting
|
129
132
|
|
130
133
|
loop do
|
131
134
|
|
132
135
|
unless date_match?(time)
|
133
|
-
time += (24 - time.hour) * 3600 - time.min * 60 - time.sec
|
134
|
-
next
|
136
|
+
time += (24 - time.hour) * 3600 - time.min * 60 - time.sec; next
|
135
137
|
end
|
136
138
|
unless sub_match?(time, :hour, @hours)
|
137
|
-
time += (60 - time.min) * 60 - time.sec
|
138
|
-
next
|
139
|
+
time += (60 - time.min) * 60 - time.sec; next
|
139
140
|
end
|
140
141
|
unless sub_match?(time, :min, @minutes)
|
141
|
-
time += 60 - time.sec
|
142
|
-
next
|
142
|
+
time += 60 - time.sec; next
|
143
143
|
end
|
144
144
|
unless sub_match?(time, :sec, @seconds)
|
145
|
-
time += 1
|
146
|
-
next
|
145
|
+
time += 1; next
|
147
146
|
end
|
148
147
|
|
149
148
|
break
|
@@ -157,6 +156,28 @@ module Rufus
|
|
157
156
|
time
|
158
157
|
end
|
159
158
|
|
159
|
+
# Returns the previous the cronline matched. It's like next_time, but
|
160
|
+
# for the past.
|
161
|
+
#
|
162
|
+
def previous_time(now=Time.now)
|
163
|
+
|
164
|
+
# looks back by slices of two hours,
|
165
|
+
#
|
166
|
+
# finds for '* * * * sun', '* * 13 * *' and '0 12 13 * *'
|
167
|
+
# starting 1970, 1, 1 in 1.8 to 2 seconds (says Rspec)
|
168
|
+
|
169
|
+
start = current = now - 2 * 3600
|
170
|
+
result = nil
|
171
|
+
|
172
|
+
loop do
|
173
|
+
nex = next_time(current)
|
174
|
+
return (result ? result : previous_time(start)) if nex > now
|
175
|
+
result = current = nex
|
176
|
+
end
|
177
|
+
|
178
|
+
# never reached
|
179
|
+
end
|
180
|
+
|
160
181
|
# Returns an array of 6 arrays (seconds, minutes, hours, days,
|
161
182
|
# months, weekdays).
|
162
183
|
# This method is used by the cronline unit tests.
|
@@ -190,15 +211,18 @@ module Rufus
|
|
190
211
|
|
191
212
|
items.each do |it|
|
192
213
|
|
193
|
-
if it.match(
|
214
|
+
if m = it.match(/^(.+)#(l|-?[12345])$/)
|
194
215
|
|
195
216
|
raise ArgumentError.new(
|
196
217
|
"ranges are not supported for monthdays (#{it})"
|
197
|
-
) if
|
218
|
+
) if m[1].index('-')
|
219
|
+
|
220
|
+
expr = it.gsub(/#l/, '#-1')
|
198
221
|
|
199
|
-
(monthdays ||= []) <<
|
222
|
+
(monthdays ||= []) << expr
|
200
223
|
|
201
224
|
else
|
225
|
+
|
202
226
|
expr = it.dup
|
203
227
|
WEEKDAYS.each_with_index { |a, i| expr.gsub!(/#{a}/, i.to_s) }
|
204
228
|
|
@@ -221,110 +245,109 @@ module Rufus
|
|
221
245
|
def parse_item(item, min, max)
|
222
246
|
|
223
247
|
return nil if item == '*'
|
224
|
-
return [ 'L' ] if item == 'L'
|
225
|
-
return parse_list(item, min, max) if item.index(',')
|
226
|
-
return parse_range(item, min, max) if item.match(/[*-\/]/)
|
227
248
|
|
228
|
-
|
229
|
-
|
230
|
-
i = min if i < min
|
231
|
-
i = max if i > max
|
232
|
-
|
233
|
-
[ i ]
|
234
|
-
end
|
235
|
-
|
236
|
-
def parse_list(item, min, max)
|
237
|
-
|
238
|
-
l = item.split(',').collect { |i| parse_range(i, min, max) }.flatten
|
249
|
+
r = item.split(',').map { |i| parse_range(i.strip, min, max) }.flatten
|
239
250
|
|
240
251
|
raise ArgumentError.new(
|
241
252
|
"found duplicates in #{item.inspect}"
|
242
|
-
) if
|
253
|
+
) if r.uniq.size < r.size
|
243
254
|
|
244
|
-
|
255
|
+
r
|
245
256
|
end
|
246
257
|
|
258
|
+
RANGE_REGEX = /^(\*|\d{1,2})(?:-(\d{1,2}))?(?:\/(\d{1,2}))?$/
|
259
|
+
|
247
260
|
def parse_range(item, min, max)
|
248
261
|
|
249
|
-
|
250
|
-
slash = item.index('/')
|
262
|
+
return %w[ L ] if item == 'L'
|
251
263
|
|
252
|
-
|
264
|
+
m = item.match(RANGE_REGEX)
|
253
265
|
|
254
266
|
raise ArgumentError.new(
|
255
|
-
"
|
256
|
-
|
257
|
-
) if item.index('L')
|
267
|
+
"cannot parse #{item.inspect}"
|
268
|
+
) unless m
|
258
269
|
|
259
|
-
|
270
|
+
sta = m[1]
|
271
|
+
sta = sta == '*' ? min : sta.to_i
|
260
272
|
|
261
|
-
|
262
|
-
|
273
|
+
edn = m[2]
|
274
|
+
edn = edn ? edn.to_i : sta
|
275
|
+
edn = max if m[1] == '*'
|
263
276
|
|
264
|
-
|
277
|
+
inc = m[3]
|
278
|
+
inc = inc ? inc.to_i : 1
|
265
279
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
else # case */x
|
270
|
-
|
271
|
-
istart = min
|
272
|
-
iend = max
|
273
|
-
end
|
274
|
-
|
275
|
-
istart = min if istart < min
|
276
|
-
iend = max if iend > max
|
280
|
+
raise ArgumentError.new(
|
281
|
+
"#{item.inspect} is not in range #{min}..#{max}"
|
282
|
+
) if sta < min or edn > max
|
277
283
|
|
278
|
-
|
284
|
+
r = []
|
285
|
+
val = sta
|
279
286
|
|
280
|
-
value = istart
|
281
287
|
loop do
|
282
|
-
|
283
|
-
|
284
|
-
|
288
|
+
v = val
|
289
|
+
v = 0 if max == 24 && v == 24
|
290
|
+
r << v
|
291
|
+
break if inc == 1 && val == edn
|
292
|
+
val += inc
|
293
|
+
break if inc > 1 && val > edn
|
294
|
+
val = min if val > max
|
285
295
|
end
|
286
296
|
|
287
|
-
|
297
|
+
r.uniq
|
288
298
|
end
|
289
299
|
|
290
|
-
def sub_match?(time, accessor, values
|
300
|
+
def sub_match?(time, accessor, values)
|
291
301
|
|
292
|
-
value
|
293
|
-
if values == :none
|
294
|
-
[ time, accessor ]
|
295
|
-
else
|
296
|
-
[ time.send(accessor), values ]
|
297
|
-
end
|
302
|
+
value = time.send(accessor)
|
298
303
|
|
299
304
|
return true if values.nil?
|
300
|
-
return true if values.include?('L') && (time +
|
305
|
+
return true if values.include?('L') && (time + DAY_S).day == 1
|
306
|
+
|
307
|
+
return true if value == 0 && accessor == :hour && values.include?(24)
|
301
308
|
|
302
309
|
values.include?(value)
|
303
310
|
end
|
304
311
|
|
312
|
+
def monthday_match?(date, values)
|
313
|
+
|
314
|
+
return true if values.nil?
|
315
|
+
|
316
|
+
today_values = monthdays(date)
|
317
|
+
|
318
|
+
(today_values & values).any?
|
319
|
+
end
|
320
|
+
|
305
321
|
def date_match?(date)
|
306
322
|
|
307
323
|
return false unless sub_match?(date, :day, @days)
|
308
324
|
return false unless sub_match?(date, :month, @months)
|
309
325
|
return false unless sub_match?(date, :wday, @weekdays)
|
310
|
-
return false unless
|
326
|
+
return false unless monthday_match?(date, @monthdays)
|
311
327
|
true
|
312
328
|
end
|
313
329
|
|
314
|
-
|
330
|
+
def monthdays(date)
|
331
|
+
|
332
|
+
pos = 1
|
333
|
+
d = date.dup
|
315
334
|
|
316
|
-
|
335
|
+
loop do
|
336
|
+
d = d - WEEK_S
|
337
|
+
break if d.month != date.month
|
338
|
+
pos = pos + 1
|
339
|
+
end
|
317
340
|
|
318
|
-
|
319
|
-
|
341
|
+
neg = -1
|
342
|
+
d = date.dup
|
320
343
|
|
321
344
|
loop do
|
322
|
-
|
323
|
-
break if
|
324
|
-
|
345
|
+
d = d + WEEK_S
|
346
|
+
break if d.month != date.month
|
347
|
+
neg = neg - 1
|
325
348
|
end
|
326
349
|
|
327
|
-
"#{WEEKDAYS[date.wday]}##{
|
350
|
+
[ "#{WEEKDAYS[date.wday]}##{pos}", "#{WEEKDAYS[date.wday]}##{neg}" ]
|
328
351
|
end
|
329
352
|
end
|
330
353
|
end
|
data/lib/rufus/sc/jobs.rb
CHANGED
data/lib/rufus/sc/rtime.rb
CHANGED
data/lib/rufus/sc/scheduler.rb
CHANGED
@@ -327,6 +327,21 @@ module Rufus::Scheduler
|
|
327
327
|
}.compact
|
328
328
|
end
|
329
329
|
|
330
|
+
# This is a blocking call, it will return when all the jobs have been
|
331
|
+
# unscheduled, waiting for any running one to finish before unscheduling
|
332
|
+
# it.
|
333
|
+
#
|
334
|
+
def terminate_all_jobs
|
335
|
+
|
336
|
+
all_jobs.each do |job_id, job|
|
337
|
+
job.unschedule
|
338
|
+
end
|
339
|
+
|
340
|
+
while running_jobs.size > 0
|
341
|
+
sleep 0.01
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
330
345
|
protected
|
331
346
|
|
332
347
|
# Returns a job queue instance.
|
@@ -455,9 +470,23 @@ module Rufus::Scheduler
|
|
455
470
|
"#{self.class} - #{Rufus::Scheduler::VERSION}"
|
456
471
|
end
|
457
472
|
|
473
|
+
# Stops this scheduler.
|
474
|
+
#
|
475
|
+
# == :terminate => true
|
476
|
+
#
|
477
|
+
# If the option :terminate is set to true,
|
478
|
+
# the method will return once all the jobs have been unscheduled and
|
479
|
+
# are done with their current run if any.
|
480
|
+
#
|
481
|
+
# (note that if a job is
|
482
|
+
# currently running, this method will wait for it to terminate, it
|
483
|
+
# will not interrupt the job run).
|
484
|
+
#
|
458
485
|
def stop(opts={})
|
459
486
|
|
460
487
|
@thread.exit
|
488
|
+
|
489
|
+
terminate_all_jobs if opts[:terminate]
|
461
490
|
end
|
462
491
|
|
463
492
|
def join
|
@@ -487,9 +516,24 @@ module Rufus::Scheduler
|
|
487
516
|
end
|
488
517
|
end
|
489
518
|
|
490
|
-
|
519
|
+
|
520
|
+
# Stops this scheduler.
|
521
|
+
#
|
522
|
+
# == :terminate => true
|
523
|
+
#
|
524
|
+
# If the option :terminate is set to true,
|
525
|
+
# the method will return once all the jobs have been unscheduled and
|
526
|
+
# are done with their current run if any.
|
527
|
+
#
|
528
|
+
# (note that if a job is
|
529
|
+
# currently running, this method will wait for it to terminate, it
|
530
|
+
# will not interrupt the job run).
|
531
|
+
#
|
532
|
+
def stop(opts={})
|
491
533
|
|
492
534
|
trap(@options[:signal] || 10)
|
535
|
+
|
536
|
+
terminate_all_jobs if opts[:terminate]
|
493
537
|
end
|
494
538
|
end
|
495
539
|
|
@@ -530,13 +574,27 @@ module Rufus::Scheduler
|
|
530
574
|
|
531
575
|
# Stops the scheduler.
|
532
576
|
#
|
577
|
+
# == :stop_em => true
|
578
|
+
#
|
533
579
|
# If the :stop_em option is passed and set to true, it will stop the
|
534
580
|
# EventMachine (but only if it started the EM by itself !).
|
535
581
|
#
|
582
|
+
# == :terminate => true
|
583
|
+
#
|
584
|
+
# If the option :terminate is set to true,
|
585
|
+
# the method will return once all the jobs have been unscheduled and
|
586
|
+
# are done with their current run if any.
|
587
|
+
#
|
588
|
+
# (note that if a job is
|
589
|
+
# currently running, this method will wait for it to terminate, it
|
590
|
+
# will not interrupt the job run).
|
591
|
+
#
|
536
592
|
def stop(opts={})
|
537
593
|
|
538
594
|
@timer.cancel
|
539
595
|
|
596
|
+
terminate_all_jobs if opts[:terminate]
|
597
|
+
|
540
598
|
EM.stop if opts[:stop_em] and @em_thread
|
541
599
|
end
|
542
600
|
|
data/lib/rufus/sc/version.rb
CHANGED
data/lib/rufus/scheduler.rb
CHANGED
@@ -28,6 +28,13 @@ require 'rufus/sc/scheduler'
|
|
28
28
|
|
29
29
|
module Rufus::Scheduler
|
30
30
|
|
31
|
+
# Starts and return a new instance of a PlainScheduler.
|
32
|
+
#
|
33
|
+
def self.new(opts={})
|
34
|
+
|
35
|
+
PlainScheduler.start_new(opts)
|
36
|
+
end
|
37
|
+
|
31
38
|
# A quick way to get a scheduler up an running
|
32
39
|
#
|
33
40
|
# require 'rubygems'
|
data/spec/cronline_spec.rb
CHANGED
@@ -24,13 +24,6 @@ describe Rufus::CronLine do
|
|
24
24
|
cl(line).to_array.should == array
|
25
25
|
end
|
26
26
|
|
27
|
-
def local(*args)
|
28
|
-
Time.local(*args)
|
29
|
-
end
|
30
|
-
def utc(*args)
|
31
|
-
Time.utc(*args)
|
32
|
-
end
|
33
|
-
|
34
27
|
describe '.new' do
|
35
28
|
|
36
29
|
it 'interprets cron strings correctly' do
|
@@ -54,6 +47,13 @@ describe Rufus::CronLine do
|
|
54
47
|
to_a '1-5 * * * * *', [ [1,2,3,4,5], nil, nil, nil, nil, nil, nil, nil ]
|
55
48
|
|
56
49
|
to_a '0 0 1 1 *', [ [0], [0], [0], [1], [1], nil, nil, nil ]
|
50
|
+
|
51
|
+
to_a '0 23-24 * * *', [ [0], [0], [23, 0], nil, nil, nil, nil, nil ]
|
52
|
+
#
|
53
|
+
# as reported by Aimee Rose in
|
54
|
+
# https://github.com/jmettraux/rufus-scheduler/issues/56
|
55
|
+
|
56
|
+
to_a '0 23-2 * * *', [ [0], [0], [23, 0, 1, 2], nil, nil, nil, nil, nil ]
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'rejects invalid weekday expressions' do
|
@@ -84,7 +84,7 @@ describe Rufus::CronLine do
|
|
84
84
|
|
85
85
|
to_a(
|
86
86
|
'0 */2 * * *',
|
87
|
-
[ [0], [0], (0..
|
87
|
+
[ [0], [0], (0..11).collect { |e| e * 2 }, nil, nil, nil, nil, nil ])
|
88
88
|
to_a(
|
89
89
|
'0 7-23/2 * * *',
|
90
90
|
[ [0], [0], (7..23).select { |e| e.odd? }, nil, nil, nil, nil, nil ])
|
@@ -105,7 +105,8 @@ describe Rufus::CronLine do
|
|
105
105
|
to_a '09 * * * *', [ [0], [9], nil, nil, nil, nil, nil, nil ]
|
106
106
|
to_a '09-12 * * * *', [ [0], [9, 10, 11, 12], nil, nil, nil, nil, nil, nil ]
|
107
107
|
to_a '07-08 * * * *', [ [0], [7, 8], nil, nil, nil, nil, nil, nil ]
|
108
|
-
to_a '* */08 * * *', [ [0], nil, [0, 8, 16
|
108
|
+
to_a '* */08 * * *', [ [0], nil, [0, 8, 16], nil, nil, nil, nil, nil ]
|
109
|
+
to_a '* */07 * * *', [ [0], nil, [0, 7, 14, 21], nil, nil, nil, nil, nil ]
|
109
110
|
to_a '* 01-09/04 * * *', [ [0], nil, [1, 5, 9], nil, nil, nil, nil, nil ]
|
110
111
|
to_a '* * * * 06', [ [0], nil, nil, nil, nil, [6], nil, nil ]
|
111
112
|
end
|
@@ -132,6 +133,18 @@ describe Rufus::CronLine do
|
|
132
133
|
|
133
134
|
lambda { cl '* L * * *'}.should raise_error(ArgumentError)
|
134
135
|
end
|
136
|
+
|
137
|
+
it 'raises for out of range input' do
|
138
|
+
|
139
|
+
lambda { cl '60-62 * * * *'}.should raise_error(ArgumentError)
|
140
|
+
lambda { cl '62 * * * *'}.should raise_error(ArgumentError)
|
141
|
+
lambda { cl '60 * * * *'}.should raise_error(ArgumentError)
|
142
|
+
lambda { cl '* 25-26 * * *'}.should raise_error(ArgumentError)
|
143
|
+
lambda { cl '* 25 * * *'}.should raise_error(ArgumentError)
|
144
|
+
#
|
145
|
+
# as reported by Aimee Rose in
|
146
|
+
# https://github.com/jmettraux/rufus-scheduler/pull/58
|
147
|
+
end
|
135
148
|
end
|
136
149
|
|
137
150
|
describe '#next_time' do
|
@@ -151,9 +164,16 @@ describe Rufus::CronLine do
|
|
151
164
|
|
152
165
|
nt('10 12 13 12 *', now).should == now + 29938200
|
153
166
|
# this one is slow (1 year == 3 seconds)
|
167
|
+
#
|
168
|
+
# historical note:
|
169
|
+
# (comment made in 2006 or 2007, the underlying libs got better and
|
170
|
+
# that slowness is gone)
|
154
171
|
|
155
172
|
nt('0 0 * * thu', now).should == now + 604800
|
156
173
|
|
174
|
+
nt('0 0 * * *', now).should == now + 24 * 3600
|
175
|
+
nt('0 24 * * *', now).should == now + 24 * 3600
|
176
|
+
|
157
177
|
now = local(2008, 12, 31, 23, 59, 59, 0)
|
158
178
|
|
159
179
|
nt('* * * * *', now).should == now + 1
|
@@ -225,34 +245,56 @@ describe Rufus::CronLine do
|
|
225
245
|
|
226
246
|
it 'computes the next time correctly when there is a sun#2 involved' do
|
227
247
|
|
228
|
-
|
248
|
+
nt('* * * * sun#1', local(1970, 1, 1)).should == local(1970, 1, 4)
|
249
|
+
nt('* * * * sun#2', local(1970, 1, 1)).should == local(1970, 1, 11)
|
229
250
|
|
230
|
-
nt('* * * * sun#
|
231
|
-
|
251
|
+
nt('* * * * sun#2', local(1970, 1, 12)).should == local(1970, 2, 8)
|
252
|
+
end
|
232
253
|
|
233
|
-
|
254
|
+
it 'computes the next time correctly when there is a sun#2,sun#3 involved' do
|
234
255
|
|
235
|
-
nt('* * * * sun#2',
|
256
|
+
nt('* * * * sun#2,sun#3', local(1970, 1, 1)).should == local(1970, 1, 11)
|
257
|
+
nt('* * * * sun#2,sun#3', local(1970, 1, 12)).should == local(1970, 1, 18)
|
236
258
|
end
|
237
259
|
|
238
|
-
it '
|
260
|
+
it 'understands sun#L' do
|
239
261
|
|
240
|
-
|
262
|
+
nt('* * * * sun#L', local(1970, 1, 1)).should == local(1970, 1, 25)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'understands sun#-1' do
|
266
|
+
|
267
|
+
nt('* * * * sun#-1', local(1970, 1, 1)).should == local(1970, 1, 25)
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'understands sun#-2' do
|
271
|
+
|
272
|
+
nt('* * * * sun#-2', local(1970, 1, 1)).should == local(1970, 1, 18)
|
273
|
+
end
|
241
274
|
|
242
|
-
|
275
|
+
it 'computes the next time correctly when "L" (last day of month)' do
|
243
276
|
|
244
|
-
|
277
|
+
nt('* * L * *', lo(1970, 1, 1)).should == lo(1970, 1, 31)
|
278
|
+
nt('* * L * *', lo(1970, 2, 1)).should == lo(1970, 2, 28)
|
279
|
+
nt('* * L * *', lo(1972, 2, 1)).should == lo(1972, 2, 29)
|
280
|
+
nt('* * L * *', lo(1970, 4, 1)).should == lo(1970, 4, 30)
|
281
|
+
end
|
282
|
+
end
|
245
283
|
|
246
|
-
|
284
|
+
describe '#previous_time' do
|
285
|
+
|
286
|
+
def pt(cronline, now)
|
287
|
+
Rufus::CronLine.new(cronline).previous_time(now)
|
247
288
|
end
|
248
289
|
|
249
|
-
|
290
|
+
it 'returns the previous time the cron should have triggered' do
|
291
|
+
|
292
|
+
pt('* * * * sun', lo(1970, 1, 1)).should == lo(1969, 12, 28, 23, 59, 00)
|
293
|
+
pt('* * 13 * *', lo(1970, 1, 1)).should == lo(1969, 12, 13, 23, 59, 00)
|
294
|
+
pt('0 12 13 * *', lo(1970, 1, 1)).should == lo(1969, 12, 13, 12, 00)
|
250
295
|
|
251
|
-
|
252
|
-
|
253
|
-
nt('* * L * *', local(1972,2,1)).should == local(1972, 2, 29)
|
254
|
-
nt('* * L * *', local(1970,4,1)).should == local(1970, 4, 30)
|
255
|
-
end
|
296
|
+
pt('* * * * * sun', lo(1970, 1, 1)).should == lo(1969, 12, 28, 23, 59, 59)
|
297
|
+
end
|
256
298
|
end
|
257
299
|
|
258
300
|
describe '#matches?' do
|
@@ -325,16 +367,21 @@ describe Rufus::CronLine do
|
|
325
367
|
end
|
326
368
|
end
|
327
369
|
|
328
|
-
describe '
|
370
|
+
describe '#monthdays' do
|
329
371
|
|
330
372
|
it 'returns the appropriate "sun#2"-like string' do
|
331
373
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
374
|
+
class Rufus::CronLine
|
375
|
+
public :monthdays
|
376
|
+
end
|
377
|
+
|
378
|
+
cl = Rufus::CronLine.new('* * * * *')
|
379
|
+
|
380
|
+
cl.monthdays(local(1970, 1, 1)).should == %w[ thu#1 thu#-5 ]
|
381
|
+
cl.monthdays(local(1970, 1, 7)).should == %w[ wed#1 wed#-4 ]
|
382
|
+
cl.monthdays(local(1970, 1, 14)).should == %w[ wed#2 wed#-3 ]
|
336
383
|
|
337
|
-
|
384
|
+
cl.monthdays(local(2011, 3, 11)).should == %w[ fri#2 fri#-3 ]
|
338
385
|
end
|
339
386
|
end
|
340
387
|
end
|
data/spec/exception_spec.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
#
|
3
2
|
# Specifying rufus-scheduler
|
4
3
|
#
|
@@ -93,5 +92,22 @@ describe SCHEDULER_CLASS do
|
|
93
92
|
$j.class.should == Rufus::Scheduler::InJob
|
94
93
|
$e.to_s.should == 'Houston we have a problem'
|
95
94
|
end
|
95
|
+
|
96
|
+
it 'allow custom exception rescue' do
|
97
|
+
@s.options[:exception]= StandardError
|
98
|
+
|
99
|
+
job = @s.in 0 do
|
100
|
+
exit
|
101
|
+
end
|
102
|
+
|
103
|
+
@e= nil
|
104
|
+
begin
|
105
|
+
wait_next_tick
|
106
|
+
rescue SystemExit => e
|
107
|
+
@e= e
|
108
|
+
end
|
109
|
+
|
110
|
+
@e.should_not == nil
|
111
|
+
end
|
96
112
|
end
|
97
113
|
|
data/spec/rtime_spec.rb
CHANGED
data/spec/scheduler_spec.rb
CHANGED
@@ -200,6 +200,38 @@ describe SCHEDULER_CLASS do
|
|
200
200
|
end
|
201
201
|
end
|
202
202
|
end
|
203
|
+
|
204
|
+
context 'termination' do
|
205
|
+
|
206
|
+
describe '#stop(true)' do
|
207
|
+
|
208
|
+
it 'terminates the scheduler, blocking until all the jobs are unscheduled' do
|
209
|
+
|
210
|
+
$every = nil
|
211
|
+
$cron = nil
|
212
|
+
|
213
|
+
s = start_scheduler
|
214
|
+
s.every '1s' do
|
215
|
+
$every = :in
|
216
|
+
sleep 0.5
|
217
|
+
$every = :out
|
218
|
+
end
|
219
|
+
s.cron '* * * * * *' do
|
220
|
+
$cron = :in
|
221
|
+
sleep 0.5
|
222
|
+
$cron = :out
|
223
|
+
end
|
224
|
+
|
225
|
+
sleep 2
|
226
|
+
|
227
|
+
s.stop(:terminate => true)
|
228
|
+
|
229
|
+
s.jobs.size.should == 0
|
230
|
+
$every.should == :out
|
231
|
+
$cron.should == :out
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
203
235
|
end
|
204
236
|
|
205
237
|
describe 'Rufus::Scheduler#start_new' do
|
data/spec/spec_base.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rufus-scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.20
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: tzinfo
|
@@ -67,39 +67,38 @@ extensions: []
|
|
67
67
|
extra_rdoc_files: []
|
68
68
|
files:
|
69
69
|
- Rakefile
|
70
|
-
- lib/rufus
|
71
|
-
- lib/rufus/
|
72
|
-
- lib/rufus/sc/jobqueues.rb
|
73
|
-
- lib/rufus/sc/jobs.rb
|
74
|
-
- lib/rufus/sc/rtime.rb
|
70
|
+
- lib/rufus-scheduler.rb
|
71
|
+
- lib/rufus/scheduler.rb
|
75
72
|
- lib/rufus/sc/scheduler.rb
|
73
|
+
- lib/rufus/sc/rtime.rb
|
76
74
|
- lib/rufus/sc/version.rb
|
77
|
-
- lib/rufus/
|
78
|
-
- lib/rufus
|
79
|
-
-
|
80
|
-
-
|
81
|
-
- spec/
|
82
|
-
- spec/
|
83
|
-
- spec/
|
84
|
-
- spec/every_spec.rb
|
75
|
+
- lib/rufus/sc/cronline.rb
|
76
|
+
- lib/rufus/sc/jobs.rb
|
77
|
+
- lib/rufus/sc/jobqueues.rb
|
78
|
+
- lib/rufus/otime.rb
|
79
|
+
- spec/job_spec.rb
|
80
|
+
- spec/stress_schedule_unschedule_spec.rb
|
81
|
+
- spec/schedulable_spec.rb
|
85
82
|
- spec/exception_spec.rb
|
86
83
|
- spec/in_spec.rb
|
87
|
-
- spec/
|
88
|
-
- spec/
|
84
|
+
- spec/timeout_spec.rb
|
85
|
+
- spec/at_spec.rb
|
86
|
+
- spec/at_in_spec.rb
|
87
|
+
- spec/spec_base.rb
|
88
|
+
- spec/cronline_spec.rb
|
89
89
|
- spec/rtime_spec.rb
|
90
|
-
- spec/
|
90
|
+
- spec/mutex_spec.rb
|
91
91
|
- spec/scheduler_spec.rb
|
92
|
-
- spec/
|
93
|
-
- spec/
|
94
|
-
- spec/
|
95
|
-
- test/kjw.rb
|
92
|
+
- spec/blocking_spec.rb
|
93
|
+
- spec/every_spec.rb
|
94
|
+
- spec/cron_spec.rb
|
96
95
|
- test/t.rb
|
96
|
+
- test/kjw.rb
|
97
97
|
- rufus-scheduler.gemspec
|
98
98
|
- CHANGELOG.txt
|
99
|
-
- CREDITS.txt
|
100
|
-
- LICENSE.txt
|
101
|
-
- out.txt
|
102
99
|
- TODO.txt
|
100
|
+
- LICENSE.txt
|
101
|
+
- CREDITS.txt
|
103
102
|
- README.rdoc
|
104
103
|
homepage: http://github.com/jmettraux/rufus-scheduler
|
105
104
|
licenses: []
|
@@ -113,21 +112,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
112
|
- - ! '>='
|
114
113
|
- !ruby/object:Gem::Version
|
115
114
|
version: '0'
|
116
|
-
segments:
|
117
|
-
- 0
|
118
|
-
hash: -1513262691769122142
|
119
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
116
|
none: false
|
121
117
|
requirements:
|
122
118
|
- - ! '>='
|
123
119
|
- !ruby/object:Gem::Version
|
124
120
|
version: '0'
|
125
|
-
segments:
|
126
|
-
- 0
|
127
|
-
hash: -1513262691769122142
|
128
121
|
requirements: []
|
129
122
|
rubyforge_project: rufus
|
130
|
-
rubygems_version: 1.8.
|
123
|
+
rubygems_version: 1.8.23
|
131
124
|
signing_key:
|
132
125
|
specification_version: 3
|
133
126
|
summary: job scheduler for Ruby (at, cron, in and every jobs)
|
data/out.txt
DELETED