rufus-scheduler 1.0.7 → 1.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +11 -0
- data/CREDITS.txt +1 -0
- data/README.txt +30 -2
- data/lib/rufus/cronline.rb +304 -0
- data/lib/rufus/otime.rb +14 -0
- data/lib/rufus/scheduler.rb +194 -447
- data/test/cronline_test.rb +0 -1
- data/test/scheduler_0_test.rb +7 -5
- data/test/scheduler_1_test.rb +3 -5
- data/test/scheduler_3_test.rb +1 -1
- data/test/scheduler_4_test.rb +1 -1
- data/test/scheduler_7_test.rb +51 -0
- data/test/test.rb +1 -0
- metadata +5 -3
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
+
== rufus-scheduler - 1.0.8 released 2008/07/18
|
6
|
+
|
7
|
+
- todo #21251 : added 'at', 'cron', 'in' and 'every' shortcut methods
|
8
|
+
- todo #21203 : keeping track of At and EveryJob until last trigger is over
|
9
|
+
- todo #20823 : now raising exception in case of bad 'at' parameter
|
10
|
+
- todo #21194 : added trigger_thread to Job class
|
11
|
+
- todo #21193 : spinned CronLine out to rufus/cronline.rb
|
12
|
+
- bug #20893 : sometimes unschedule(every_job) not working when job was
|
13
|
+
active (performing). Fixed.
|
14
|
+
|
15
|
+
|
5
16
|
== rufus-scheduler - 1.0.7 released 2008/06/16
|
6
17
|
|
7
18
|
- todo #20669 : implemented CronJob.next_time()
|
data/CREDITS.txt
CHANGED
data/README.txt
CHANGED
@@ -17,7 +17,35 @@ http://rubyforge.org/frs/?group_id=4812
|
|
17
17
|
|
18
18
|
== usage
|
19
19
|
|
20
|
-
|
20
|
+
some examples :
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'rufus/scheduler'
|
24
|
+
|
25
|
+
scheduler = Rufus::Scheduler.start_new
|
26
|
+
|
27
|
+
scheduler.in("3d") do
|
28
|
+
regenerate_monthly_report()
|
29
|
+
end
|
30
|
+
#
|
31
|
+
# will call the regenerate_monthly_report method
|
32
|
+
# in 3 days from now
|
33
|
+
|
34
|
+
scheduler.every "10m10s" do
|
35
|
+
check_score(favourite_team) # every 10 minutes and 10 seconds
|
36
|
+
end
|
37
|
+
|
38
|
+
scheduler.cron "0 22 * * 1-5" do
|
39
|
+
log.info "activating security system..."
|
40
|
+
activate_security_system()
|
41
|
+
end
|
42
|
+
|
43
|
+
job_id = scheduler.at "Sun Oct 07 14:24:01 +0900 2009" do
|
44
|
+
init_self_destruction_sequence()
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
For all the scheduling related information, see the Rufus::Scheduler class rdoc itself (http://rufus.rubyforge.org/rufus-scheduler/classes/Rufus/Scheduler.html) or the original OpenWFEru scheduler documentation at http://openwferu.rubyforge.org/scheduler.html
|
21
49
|
|
22
50
|
Apart from scheduling, There are also two interesting methods in this gem, they are named parse_time_string and to_time_string :
|
23
51
|
|
@@ -66,7 +94,7 @@ http://github.com/jmettraux/rufus-scheduler
|
|
66
94
|
|
67
95
|
== author
|
68
96
|
|
69
|
-
John Mettraux, jmettraux@gmail.com
|
97
|
+
John Mettraux, jmettraux@gmail.com
|
70
98
|
http://jmettraux.wordpress.com
|
71
99
|
|
72
100
|
|
@@ -0,0 +1,304 @@
|
|
1
|
+
#
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2006-2008, John Mettraux, jmettraux@gmail.com
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
#
|
24
|
+
|
25
|
+
#
|
26
|
+
# "made in Japan"
|
27
|
+
#
|
28
|
+
# John Mettraux at openwfe.org
|
29
|
+
#
|
30
|
+
|
31
|
+
module Rufus
|
32
|
+
|
33
|
+
#
|
34
|
+
# A 'cron line' is a line in the sense of a crontab
|
35
|
+
# (man 5 crontab) file line.
|
36
|
+
#
|
37
|
+
class CronLine
|
38
|
+
|
39
|
+
#
|
40
|
+
# The string used for creating this cronline instance.
|
41
|
+
#
|
42
|
+
attr_reader :original
|
43
|
+
|
44
|
+
attr_reader \
|
45
|
+
:seconds,
|
46
|
+
:minutes,
|
47
|
+
:hours,
|
48
|
+
:days,
|
49
|
+
:months,
|
50
|
+
:weekdays
|
51
|
+
|
52
|
+
def initialize (line)
|
53
|
+
|
54
|
+
super()
|
55
|
+
|
56
|
+
@original = line
|
57
|
+
|
58
|
+
items = line.split
|
59
|
+
|
60
|
+
unless [ 5, 6 ].include?(items.length)
|
61
|
+
raise \
|
62
|
+
"cron '#{line}' string should hold 5 or 6 items, " +
|
63
|
+
"not #{items.length}" \
|
64
|
+
end
|
65
|
+
|
66
|
+
offset = items.length - 5
|
67
|
+
|
68
|
+
@seconds = if offset == 1
|
69
|
+
parse_item(items[0], 0, 59)
|
70
|
+
else
|
71
|
+
[ 0 ]
|
72
|
+
end
|
73
|
+
@minutes = parse_item(items[0+offset], 0, 59)
|
74
|
+
@hours = parse_item(items[1+offset], 0, 24)
|
75
|
+
@days = parse_item(items[2+offset], 1, 31)
|
76
|
+
@months = parse_item(items[3+offset], 1, 12)
|
77
|
+
@weekdays = parse_weekdays(items[4+offset])
|
78
|
+
|
79
|
+
#adjust_arrays()
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Returns true if the given time matches this cron line.
|
84
|
+
#
|
85
|
+
# (the precision is passed as well to determine if it's
|
86
|
+
# worth checking seconds and minutes)
|
87
|
+
#
|
88
|
+
def matches? (time)
|
89
|
+
#def matches? (time, precision)
|
90
|
+
|
91
|
+
time = Time.at(time) unless time.kind_of?(Time)
|
92
|
+
|
93
|
+
return false \
|
94
|
+
if no_match?(time.sec, @seconds)
|
95
|
+
#if precision <= 1 and no_match?(time.sec, @seconds)
|
96
|
+
return false \
|
97
|
+
if no_match?(time.min, @minutes)
|
98
|
+
#if precision <= 60 and no_match?(time.min, @minutes)
|
99
|
+
return false \
|
100
|
+
if no_match?(time.hour, @hours)
|
101
|
+
return false \
|
102
|
+
if no_match?(time.day, @days)
|
103
|
+
return false \
|
104
|
+
if no_match?(time.month, @months)
|
105
|
+
return false \
|
106
|
+
if no_match?(time.wday, @weekdays)
|
107
|
+
|
108
|
+
true
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Returns an array of 6 arrays (seconds, minutes, hours, days,
|
113
|
+
# months, weekdays).
|
114
|
+
# This method is used by the cronline unit tests.
|
115
|
+
#
|
116
|
+
def to_array
|
117
|
+
|
118
|
+
[ @seconds, @minutes, @hours, @days, @months, @weekdays ]
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Returns the next time that this cron line is supposed to 'fire'
|
123
|
+
#
|
124
|
+
# This is raw, 3 secs to iterate over 1 year on my macbook :( brutal.
|
125
|
+
#
|
126
|
+
def next_time (now = Time.now)
|
127
|
+
|
128
|
+
#
|
129
|
+
# position now to the next cron second
|
130
|
+
|
131
|
+
if @seconds
|
132
|
+
next_sec = @seconds.find { |s| s > now.sec } || 60 + @seconds.first
|
133
|
+
now += next_sec - now.sec
|
134
|
+
else
|
135
|
+
now += 1
|
136
|
+
end
|
137
|
+
|
138
|
+
#
|
139
|
+
# prepare sec jump array
|
140
|
+
|
141
|
+
sjarray = nil
|
142
|
+
|
143
|
+
if @seconds
|
144
|
+
|
145
|
+
sjarray = []
|
146
|
+
|
147
|
+
i = @seconds.index(now.sec)
|
148
|
+
ii = i
|
149
|
+
|
150
|
+
loop do
|
151
|
+
cur = @seconds[ii]
|
152
|
+
ii += 1
|
153
|
+
ii = 0 if ii == @seconds.size
|
154
|
+
nxt = @seconds[ii]
|
155
|
+
nxt += 60 if ii == 0
|
156
|
+
sjarray << (nxt - cur)
|
157
|
+
break if ii == i
|
158
|
+
end
|
159
|
+
|
160
|
+
else
|
161
|
+
|
162
|
+
sjarray = [ 1 ]
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# ok, seek...
|
167
|
+
|
168
|
+
i = 0
|
169
|
+
|
170
|
+
loop do
|
171
|
+
return now if matches?(now)
|
172
|
+
now += sjarray[i]
|
173
|
+
i += 1
|
174
|
+
i = 0 if i == sjarray.size
|
175
|
+
# danger... potentially no exit...
|
176
|
+
end
|
177
|
+
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
#--
|
184
|
+
# adjust values to Ruby
|
185
|
+
#
|
186
|
+
#def adjust_arrays()
|
187
|
+
# @hours = @hours.collect { |h|
|
188
|
+
# if h == 24
|
189
|
+
# 0
|
190
|
+
# else
|
191
|
+
# h
|
192
|
+
# end
|
193
|
+
# } if @hours
|
194
|
+
# @weekdays = @weekdays.collect { |wd|
|
195
|
+
# wd - 1
|
196
|
+
# } if @weekdays
|
197
|
+
#end
|
198
|
+
#
|
199
|
+
# dead code, keeping it as a reminder
|
200
|
+
#++
|
201
|
+
|
202
|
+
WDS = [ "sun", "mon", "tue", "wed", "thu", "fri", "sat" ]
|
203
|
+
#
|
204
|
+
# used by parse_weekday()
|
205
|
+
|
206
|
+
def parse_weekdays (item)
|
207
|
+
|
208
|
+
item = item.downcase
|
209
|
+
|
210
|
+
WDS.each_with_index do |day, index|
|
211
|
+
item = item.gsub day, "#{index}"
|
212
|
+
end
|
213
|
+
|
214
|
+
r = parse_item item, 0, 7
|
215
|
+
|
216
|
+
return r unless r.is_a?(Array)
|
217
|
+
|
218
|
+
r.collect { |e| e == 7 ? 0 : e }.uniq
|
219
|
+
end
|
220
|
+
|
221
|
+
def parse_item (item, min, max)
|
222
|
+
|
223
|
+
return nil \
|
224
|
+
if item == "*"
|
225
|
+
return parse_list(item, min, max) \
|
226
|
+
if item.index(",")
|
227
|
+
return parse_range(item, min, max) \
|
228
|
+
if item.index("*") or item.index("-")
|
229
|
+
|
230
|
+
i = Integer(item)
|
231
|
+
|
232
|
+
i = min if i < min
|
233
|
+
i = max if i > max
|
234
|
+
|
235
|
+
[ i ]
|
236
|
+
end
|
237
|
+
|
238
|
+
def parse_list (item, min, max)
|
239
|
+
|
240
|
+
items = item.split(",")
|
241
|
+
|
242
|
+
items.inject([]) { |r, i| r.push(parse_range(i, min, max)) }.flatten
|
243
|
+
end
|
244
|
+
|
245
|
+
def parse_range (item, min, max)
|
246
|
+
|
247
|
+
i = item.index("-")
|
248
|
+
j = item.index("/")
|
249
|
+
|
250
|
+
return item.to_i if (not i and not j)
|
251
|
+
|
252
|
+
inc = 1
|
253
|
+
|
254
|
+
inc = Integer(item[j+1..-1]) if j
|
255
|
+
|
256
|
+
istart = -1
|
257
|
+
iend = -1
|
258
|
+
|
259
|
+
if i
|
260
|
+
|
261
|
+
istart = Integer(item[0..i-1])
|
262
|
+
|
263
|
+
if j
|
264
|
+
iend = Integer(item[i+1..j])
|
265
|
+
else
|
266
|
+
iend = Integer(item[i+1..-1])
|
267
|
+
end
|
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
|
277
|
+
|
278
|
+
result = []
|
279
|
+
|
280
|
+
value = istart
|
281
|
+
loop do
|
282
|
+
|
283
|
+
result << value
|
284
|
+
value = value + inc
|
285
|
+
break if value > iend
|
286
|
+
end
|
287
|
+
|
288
|
+
result
|
289
|
+
end
|
290
|
+
|
291
|
+
def no_match? (value, cron_values)
|
292
|
+
|
293
|
+
return false if not cron_values
|
294
|
+
|
295
|
+
cron_values.each do |v|
|
296
|
+
return false if value == v # ok, it matches
|
297
|
+
end
|
298
|
+
|
299
|
+
true # no match found
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
data/lib/rufus/otime.rb
CHANGED
@@ -336,6 +336,20 @@ module Rufus
|
|
336
336
|
h
|
337
337
|
end
|
338
338
|
|
339
|
+
#
|
340
|
+
# Ensures that a duration is a expressed as a Float instance.
|
341
|
+
#
|
342
|
+
# duration_to_f("10s")
|
343
|
+
#
|
344
|
+
# will yield 10.0
|
345
|
+
#
|
346
|
+
def Rufus.duration_to_f (s)
|
347
|
+
|
348
|
+
return s if s.kind_of?(Float)
|
349
|
+
return parse_time_string(s) if s.kind_of?(String)
|
350
|
+
Float(s.to_s)
|
351
|
+
end
|
352
|
+
|
339
353
|
protected
|
340
354
|
|
341
355
|
DURATIONS2M = [
|
data/lib/rufus/scheduler.rb
CHANGED
@@ -31,7 +31,7 @@
|
|
31
31
|
require 'thread'
|
32
32
|
require 'monitor'
|
33
33
|
require 'rufus/otime'
|
34
|
-
|
34
|
+
require 'rufus/cronline'
|
35
35
|
|
36
36
|
module Rufus
|
37
37
|
|
@@ -45,7 +45,7 @@ module Rufus
|
|
45
45
|
# params (usually an array or nil), either a block, which is more in the
|
46
46
|
# Ruby way.
|
47
47
|
#
|
48
|
-
# == The gem "
|
48
|
+
# == The gem "rufus-scheduler"
|
49
49
|
#
|
50
50
|
# This scheduler was previously known as the "openwferu-scheduler" gem.
|
51
51
|
#
|
@@ -114,6 +114,9 @@ module Rufus
|
|
114
114
|
# regenerate_latest_report()
|
115
115
|
# end
|
116
116
|
#
|
117
|
+
# (note : a schedule every isn't triggered immediately, thus this example
|
118
|
+
# will first trigger 1 hour and 20 minutes after being scheduled)
|
119
|
+
#
|
117
120
|
# The scheduler has a "exit_when_no_more_jobs" attribute. When set to
|
118
121
|
# 'true', the scheduler will exit as soon as there are no more jobs to
|
119
122
|
# run.
|
@@ -287,6 +290,20 @@ module Rufus
|
|
287
290
|
#
|
288
291
|
# scheduler.new :thread_name => "the crazy scheduler"
|
289
292
|
#
|
293
|
+
#
|
294
|
+
# == job.trigger_thread
|
295
|
+
#
|
296
|
+
# Since rufus-scheduler 1.0.8, you can have access to the thread of
|
297
|
+
# a job currently being triggered.
|
298
|
+
#
|
299
|
+
# job = scheduler.get_job(job_id)
|
300
|
+
# thread = job.trigger_thread
|
301
|
+
#
|
302
|
+
# This new method will return nil if the job is not currently being
|
303
|
+
# triggered. Not that in case of an every or cron job, this method
|
304
|
+
# will return the thread of the last triggered instance, thus, in case
|
305
|
+
# of overlapping executions, you only get the most recent thread.
|
306
|
+
#
|
290
307
|
class Scheduler
|
291
308
|
|
292
309
|
#
|
@@ -324,6 +341,7 @@ module Rufus
|
|
324
341
|
|
325
342
|
@pending_jobs = []
|
326
343
|
@cron_jobs = {}
|
344
|
+
@non_cron_jobs = {}
|
327
345
|
|
328
346
|
@schedule_queue = Queue.new
|
329
347
|
@unschedule_queue = Queue.new
|
@@ -346,7 +364,7 @@ module Rufus
|
|
346
364
|
#@correction = 0.00045
|
347
365
|
|
348
366
|
@exit_when_no_more_jobs = false
|
349
|
-
|
367
|
+
#@dont_reschedule_every = false
|
350
368
|
|
351
369
|
@last_cron_second = -1
|
352
370
|
|
@@ -467,6 +485,11 @@ module Rufus
|
|
467
485
|
&block)
|
468
486
|
end
|
469
487
|
|
488
|
+
#
|
489
|
+
# a shortcut for schedule_at
|
490
|
+
#
|
491
|
+
alias :at :schedule_at
|
492
|
+
|
470
493
|
|
471
494
|
#
|
472
495
|
# Schedules a job by stating in how much time it should trigger.
|
@@ -478,11 +501,16 @@ module Rufus
|
|
478
501
|
def schedule_in (duration, params={}, &block)
|
479
502
|
|
480
503
|
do_schedule_at(
|
481
|
-
Time.new.to_f + duration_to_f(duration),
|
504
|
+
Time.new.to_f + Rufus::duration_to_f(duration),
|
482
505
|
prepare_params(params),
|
483
506
|
&block)
|
484
507
|
end
|
485
508
|
|
509
|
+
#
|
510
|
+
# a shortcut for schedule_in
|
511
|
+
#
|
512
|
+
alias :in :schedule_in
|
513
|
+
|
486
514
|
#
|
487
515
|
# Schedules a job in a loop. After an execution, it will not execute
|
488
516
|
# before the time specified in 'freq'.
|
@@ -505,76 +533,33 @@ module Rufus
|
|
505
533
|
# # schedule something every two days, start in 5 hours...
|
506
534
|
# end
|
507
535
|
#
|
536
|
+
# (without setting a :first_in (or :first_at), our example schedule would
|
537
|
+
# have had been triggered after two days).
|
538
|
+
#
|
508
539
|
def schedule_every (freq, params={}, &block)
|
509
540
|
|
510
|
-
f = duration_to_f freq
|
511
|
-
|
512
541
|
params = prepare_params params
|
513
|
-
schedulable = params[:schedulable]
|
514
542
|
params[:every] = freq
|
515
543
|
|
516
|
-
first_at = params
|
517
|
-
first_in = params
|
518
|
-
|
519
|
-
previous_at = params[:previous_at]
|
544
|
+
first_at = params[:first_at]
|
545
|
+
first_in = params[:first_in]
|
520
546
|
|
521
|
-
|
522
|
-
first_at
|
547
|
+
first_at = if first_at
|
548
|
+
at_to_f(first_at)
|
523
549
|
elsif first_in
|
524
|
-
Time.now.to_f + duration_to_f(first_in)
|
525
|
-
elsif previous_at
|
526
|
-
previous_at + f
|
550
|
+
Time.now.to_f + Rufus.duration_to_f(first_in)
|
527
551
|
else
|
528
|
-
Time.now.to_f +
|
552
|
+
Time.now.to_f + Rufus.duration_to_f(freq) # not triggering immediately
|
529
553
|
end
|
530
554
|
|
531
|
-
do_schedule_at(
|
532
|
-
|
533
|
-
#
|
534
|
-
# trigger ...
|
535
|
-
|
536
|
-
hit_exception = false
|
537
|
-
|
538
|
-
begin
|
539
|
-
|
540
|
-
if schedulable
|
541
|
-
schedulable.trigger params
|
542
|
-
else
|
543
|
-
block.call job_id, at, params
|
544
|
-
end
|
545
|
-
|
546
|
-
rescue Exception => e
|
547
|
-
|
548
|
-
log_exception e
|
549
|
-
|
550
|
-
hit_exception = true
|
551
|
-
end
|
552
|
-
|
553
|
-
# cannot use a return here !!! (block)
|
554
|
-
|
555
|
-
unless \
|
556
|
-
@dont_reschedule_every or
|
557
|
-
(params[:dont_reschedule] == true) or
|
558
|
-
(hit_exception and params[:try_again] == false)
|
559
|
-
|
560
|
-
#
|
561
|
-
# ok, reschedule ...
|
562
|
-
|
563
|
-
params[:job_id] = job_id
|
564
|
-
params[:previous_at] = at
|
565
|
-
|
566
|
-
schedule_every params[:every], params, &block
|
567
|
-
#
|
568
|
-
# yes, this is a kind of recursion
|
569
|
-
|
570
|
-
# note that params[:every] might have been changed
|
571
|
-
# by the block/schedulable code
|
572
|
-
end
|
573
|
-
|
574
|
-
job_id
|
575
|
-
end
|
555
|
+
do_schedule_at(first_at, params, &block)
|
576
556
|
end
|
577
557
|
|
558
|
+
#
|
559
|
+
# a shortcut for schedule_every
|
560
|
+
#
|
561
|
+
alias :every :schedule_every
|
562
|
+
|
578
563
|
#
|
579
564
|
# Schedules a cron job, the 'cron_line' is a string
|
580
565
|
# following the Unix cron standard (see "man 5 crontab" in your command
|
@@ -607,11 +592,9 @@ module Rufus
|
|
607
592
|
#
|
608
593
|
# is a job with the same id already scheduled ?
|
609
594
|
|
610
|
-
cron_id = params[:cron_id]
|
611
|
-
cron_id = params[:job_id] unless cron_id
|
595
|
+
cron_id = params[:cron_id] || params[:job_id]
|
612
596
|
|
613
|
-
|
614
|
-
@unschedule_queue << [ :cron, cron_id ]
|
597
|
+
#@unschedule_queue << cron_id
|
615
598
|
|
616
599
|
#
|
617
600
|
# schedule
|
@@ -619,12 +602,16 @@ module Rufus
|
|
619
602
|
b = to_block(params, &block)
|
620
603
|
job = CronJob.new(self, cron_id, cron_line, params, &b)
|
621
604
|
|
622
|
-
#@cron_jobs[job.job_id] = job
|
623
605
|
@schedule_queue << job
|
624
606
|
|
625
607
|
job.job_id
|
626
608
|
end
|
627
609
|
|
610
|
+
#
|
611
|
+
# an alias for schedule()
|
612
|
+
#
|
613
|
+
alias :cron :schedule
|
614
|
+
|
628
615
|
#--
|
629
616
|
#
|
630
617
|
# The UNscheduling methods
|
@@ -637,15 +624,17 @@ module Rufus
|
|
637
624
|
#
|
638
625
|
def unschedule (job_id)
|
639
626
|
|
640
|
-
@unschedule_queue <<
|
627
|
+
@unschedule_queue << job_id
|
641
628
|
end
|
642
629
|
|
643
630
|
#
|
644
631
|
# Unschedules a cron job
|
645
632
|
#
|
633
|
+
# (deprecated : use unschedule(job_id) for all the jobs !)
|
634
|
+
#
|
646
635
|
def unschedule_cron_job (job_id)
|
647
636
|
|
648
|
-
|
637
|
+
unschedule(job_id)
|
649
638
|
end
|
650
639
|
|
651
640
|
#--
|
@@ -660,7 +649,7 @@ module Rufus
|
|
660
649
|
#
|
661
650
|
def get_job (job_id)
|
662
651
|
|
663
|
-
@cron_jobs[job_id] || @
|
652
|
+
@cron_jobs[job_id] || @non_cron_jobs[job_id]
|
664
653
|
end
|
665
654
|
|
666
655
|
#
|
@@ -669,13 +658,8 @@ module Rufus
|
|
669
658
|
#
|
670
659
|
def get_schedulable (job_id)
|
671
660
|
|
672
|
-
#return nil unless job_id
|
673
|
-
|
674
661
|
j = get_job(job_id)
|
675
|
-
|
676
|
-
return j.schedulable if j.respond_to?(:schedulable)
|
677
|
-
|
678
|
-
nil
|
662
|
+
j.respond_to?(:schedulable) ? j.schedulable : nil
|
679
663
|
end
|
680
664
|
|
681
665
|
#
|
@@ -684,7 +668,7 @@ module Rufus
|
|
684
668
|
def find_jobs (tag)
|
685
669
|
|
686
670
|
@cron_jobs.values.find_all { |job| job.has_tag?(tag) } +
|
687
|
-
@
|
671
|
+
@non_cron_jobs.values.find_all { |job| job.has_tag?(tag) }
|
688
672
|
end
|
689
673
|
|
690
674
|
#
|
@@ -720,7 +704,7 @@ module Rufus
|
|
720
704
|
#
|
721
705
|
def every_job_count
|
722
706
|
|
723
|
-
@
|
707
|
+
@non_cron_jobs.values.select { |j| j.class == EveryJob }.size
|
724
708
|
end
|
725
709
|
|
726
710
|
#
|
@@ -728,36 +712,43 @@ module Rufus
|
|
728
712
|
#
|
729
713
|
def at_job_count
|
730
714
|
|
731
|
-
@
|
715
|
+
@non_cron_jobs.values.select { |j| j.class == AtJob }.size
|
732
716
|
end
|
733
717
|
|
734
718
|
#
|
735
719
|
# Returns true if the given string seems to be a cron string.
|
736
720
|
#
|
737
|
-
def
|
721
|
+
def self.is_cron_string (s)
|
738
722
|
|
739
723
|
s.match ".+ .+ .+ .+ .+" # well...
|
740
724
|
end
|
741
725
|
|
742
726
|
private
|
743
727
|
|
728
|
+
#
|
729
|
+
# the unschedule work itself.
|
730
|
+
#
|
744
731
|
def do_unschedule (job_id)
|
745
732
|
|
733
|
+
job = get_job job_id
|
734
|
+
|
735
|
+
return (@cron_jobs.delete(job_id) != nil) if job.is_a?(CronJob)
|
736
|
+
|
737
|
+
return false unless job # not found
|
738
|
+
|
739
|
+
if job.is_a?(AtJob) # catches AtJob and EveryJob instances
|
740
|
+
@non_cron_jobs.delete(job_id)
|
741
|
+
job.params[:dont_reschedule] = true # for AtJob as well, no worries
|
742
|
+
end
|
743
|
+
|
746
744
|
for i in 0...@pending_jobs.length
|
747
745
|
if @pending_jobs[i].job_id == job_id
|
748
746
|
@pending_jobs.delete_at i
|
749
|
-
return true
|
747
|
+
return true # asap
|
750
748
|
end
|
751
749
|
end
|
752
|
-
#
|
753
|
-
# not using delete_if because it scans the whole list
|
754
|
-
|
755
|
-
do_unschedule_cron_job job_id
|
756
|
-
end
|
757
750
|
|
758
|
-
|
759
|
-
|
760
|
-
(@cron_jobs.delete(job_id) != nil)
|
751
|
+
true
|
761
752
|
end
|
762
753
|
|
763
754
|
#
|
@@ -765,9 +756,7 @@ module Rufus
|
|
765
756
|
#
|
766
757
|
def prepare_params (params)
|
767
758
|
|
768
|
-
params
|
769
|
-
if params.is_a?(Schedulable)
|
770
|
-
params
|
759
|
+
params.is_a?(Schedulable) ? { :schedulable => params } : params
|
771
760
|
end
|
772
761
|
|
773
762
|
#
|
@@ -776,47 +765,33 @@ module Rufus
|
|
776
765
|
#
|
777
766
|
def do_schedule_at (at, params={}, &block)
|
778
767
|
|
779
|
-
|
768
|
+
job = params.delete :job
|
780
769
|
|
781
|
-
|
770
|
+
unless job
|
782
771
|
|
783
|
-
|
772
|
+
jobClass = params[:every] ? EveryJob : AtJob
|
784
773
|
|
785
|
-
|
774
|
+
b = to_block params, &block
|
786
775
|
|
787
|
-
|
788
|
-
|
789
|
-
b = to_block params, &block
|
776
|
+
job = jobClass.new self, at_to_f(at), params[:job_id], params, &b
|
777
|
+
end
|
790
778
|
|
791
|
-
|
779
|
+
if jobClass == AtJob && job.at < (Time.new.to_f + @precision)
|
792
780
|
|
793
|
-
|
781
|
+
job.trigger() unless params[:discard_past]
|
794
782
|
|
795
|
-
|
783
|
+
@non_cron_jobs.delete job.job_id # just to be sure
|
796
784
|
|
797
|
-
job.trigger() unless params[:discard_past]
|
798
785
|
return nil
|
799
786
|
end
|
800
787
|
|
788
|
+
@non_cron_jobs[job.job_id] = job
|
789
|
+
|
801
790
|
@schedule_queue << job
|
802
791
|
|
803
792
|
job.job_id
|
804
793
|
end
|
805
794
|
|
806
|
-
#
|
807
|
-
# Ensures that a duration is a expressed as a Float instance.
|
808
|
-
#
|
809
|
-
# duration_to_f("10s")
|
810
|
-
#
|
811
|
-
# will yields 10.0
|
812
|
-
#
|
813
|
-
def duration_to_f (s)
|
814
|
-
|
815
|
-
return s if s.kind_of?(Float)
|
816
|
-
return Rufus::parse_time_string(s) if s.kind_of?(String)
|
817
|
-
Float(s.to_s)
|
818
|
-
end
|
819
|
-
|
820
795
|
#
|
821
796
|
# Ensures an 'at' instance is translated to a float
|
822
797
|
# (to be compared with the float coming from time.to_f)
|
@@ -826,6 +801,9 @@ module Rufus
|
|
826
801
|
at = Rufus::to_ruby_time(at) if at.kind_of?(String)
|
827
802
|
at = Rufus::to_gm_time(at) if at.kind_of?(DateTime)
|
828
803
|
at = at.to_f if at.kind_of?(Time)
|
804
|
+
|
805
|
+
raise "cannot schedule at : #{at.inspect}" unless at.is_a?(Float)
|
806
|
+
|
829
807
|
at
|
830
808
|
end
|
831
809
|
|
@@ -838,12 +816,10 @@ module Rufus
|
|
838
816
|
|
839
817
|
return block if block
|
840
818
|
|
841
|
-
schedulable = params
|
819
|
+
schedulable = params.delete(:schedulable)
|
842
820
|
|
843
821
|
return nil unless schedulable
|
844
822
|
|
845
|
-
params.delete :schedulable
|
846
|
-
|
847
823
|
l = lambda do
|
848
824
|
schedulable.trigger(params)
|
849
825
|
end
|
@@ -886,9 +862,6 @@ module Rufus
|
|
886
862
|
#
|
887
863
|
def step
|
888
864
|
|
889
|
-
#puts Time.now.to_f
|
890
|
-
#puts @pending_jobs.collect { |j| [ j.job_id, j.at ] }.inspect
|
891
|
-
|
892
865
|
step_unschedule
|
893
866
|
# unschedules any job in the unschedule queue before
|
894
867
|
# they have a chance to get triggered.
|
@@ -911,15 +884,7 @@ module Rufus
|
|
911
884
|
|
912
885
|
break if @unschedule_queue.empty?
|
913
886
|
|
914
|
-
|
915
|
-
|
916
|
-
if type == :cron
|
917
|
-
|
918
|
-
do_unschedule_cron_job job_id
|
919
|
-
else
|
920
|
-
|
921
|
-
do_unschedule job_id
|
922
|
-
end
|
887
|
+
do_unschedule(@unschedule_queue.pop)
|
923
888
|
end
|
924
889
|
end
|
925
890
|
|
@@ -947,22 +912,17 @@ module Rufus
|
|
947
912
|
end
|
948
913
|
|
949
914
|
#
|
950
|
-
# triggers every eligible pending jobs, then every eligible
|
915
|
+
# triggers every eligible pending (at or every) jobs, then every eligible
|
951
916
|
# cron jobs.
|
952
917
|
#
|
953
918
|
def step_trigger
|
954
919
|
|
955
|
-
now = Time.
|
956
|
-
|
957
|
-
if @exit_when_no_more_jobs
|
958
|
-
|
959
|
-
if @pending_jobs.size < 1
|
920
|
+
now = Time.now
|
960
921
|
|
961
|
-
|
962
|
-
return
|
963
|
-
end
|
922
|
+
if @exit_when_no_more_jobs && @pending_jobs.size < 1
|
964
923
|
|
965
|
-
@
|
924
|
+
@stopped = true
|
925
|
+
return
|
966
926
|
end
|
967
927
|
|
968
928
|
# TODO : eventually consider running cron / pending
|
@@ -977,12 +937,9 @@ module Rufus
|
|
977
937
|
|
978
938
|
@last_cron_second = now.sec
|
979
939
|
|
980
|
-
#puts "step() @cron_jobs.size #{@cron_jobs.size}"
|
981
|
-
|
982
940
|
@cron_jobs.each do |cron_id, cron_job|
|
983
|
-
#puts "step() cron_id : #{cron_id}"
|
984
941
|
#trigger(cron_job) if cron_job.matches?(now, @precision)
|
985
|
-
trigger
|
942
|
+
cron_job.trigger if cron_job.matches?(now)
|
986
943
|
end
|
987
944
|
end
|
988
945
|
|
@@ -1005,29 +962,12 @@ module Rufus
|
|
1005
962
|
#
|
1006
963
|
# obviously
|
1007
964
|
|
1008
|
-
trigger
|
965
|
+
job.trigger
|
1009
966
|
|
1010
967
|
@pending_jobs.delete_at 0
|
1011
968
|
end
|
1012
969
|
end
|
1013
970
|
|
1014
|
-
#
|
1015
|
-
# Triggers the job (in a dedicated thread).
|
1016
|
-
#
|
1017
|
-
def trigger (job)
|
1018
|
-
|
1019
|
-
Thread.new do
|
1020
|
-
begin
|
1021
|
-
|
1022
|
-
job.trigger
|
1023
|
-
|
1024
|
-
rescue Exception => e
|
1025
|
-
|
1026
|
-
log_exception e
|
1027
|
-
end
|
1028
|
-
end
|
1029
|
-
end
|
1030
|
-
|
1031
971
|
#
|
1032
972
|
# If an error occurs in the job, it well get caught and an error
|
1033
973
|
# message will be displayed to STDOUT.
|
@@ -1108,6 +1048,12 @@ module Rufus
|
|
1108
1048
|
#
|
1109
1049
|
attr_reader :params
|
1110
1050
|
|
1051
|
+
#
|
1052
|
+
# if the job is currently executing, this field points to
|
1053
|
+
# the 'trigger thread'
|
1054
|
+
#
|
1055
|
+
attr_reader :trigger_thread
|
1056
|
+
|
1111
1057
|
|
1112
1058
|
def initialize (scheduler, job_id, params, &block)
|
1113
1059
|
|
@@ -1147,6 +1093,31 @@ module Rufus
|
|
1147
1093
|
|
1148
1094
|
@scheduler.unschedule(@job_id)
|
1149
1095
|
end
|
1096
|
+
|
1097
|
+
#
|
1098
|
+
# Triggers the job (in a dedicated thread).
|
1099
|
+
#
|
1100
|
+
def trigger
|
1101
|
+
|
1102
|
+
Thread.new do
|
1103
|
+
|
1104
|
+
@trigger_thread = Thread.current
|
1105
|
+
# keeping track of the thread
|
1106
|
+
|
1107
|
+
begin
|
1108
|
+
|
1109
|
+
do_trigger
|
1110
|
+
|
1111
|
+
rescue Exception => e
|
1112
|
+
|
1113
|
+
@scheduler.send(:log_exception, e)
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
#@trigger_thread = nil if @trigger_thread = Thread.current
|
1117
|
+
@trigger_thread = nil
|
1118
|
+
# overlapping executions, what to do ?
|
1119
|
+
end
|
1120
|
+
end
|
1150
1121
|
end
|
1151
1122
|
|
1152
1123
|
#
|
@@ -1160,23 +1131,13 @@ module Rufus
|
|
1160
1131
|
#
|
1161
1132
|
attr_accessor :at
|
1162
1133
|
|
1163
|
-
|
1164
|
-
# The constructor.
|
1165
|
-
#
|
1134
|
+
|
1166
1135
|
def initialize (scheduler, at, at_id, params, &block)
|
1167
1136
|
|
1168
1137
|
super(scheduler, at_id, params, &block)
|
1169
1138
|
@at = at
|
1170
1139
|
end
|
1171
1140
|
|
1172
|
-
#
|
1173
|
-
# Triggers the job (calls the block)
|
1174
|
-
#
|
1175
|
-
def trigger
|
1176
|
-
|
1177
|
-
@block.call @job_id, @at
|
1178
|
-
end
|
1179
|
-
|
1180
1141
|
#
|
1181
1142
|
# Returns the Time instance at which this job is scheduled.
|
1182
1143
|
#
|
@@ -1193,6 +1154,18 @@ module Rufus
|
|
1193
1154
|
|
1194
1155
|
schedule_info
|
1195
1156
|
end
|
1157
|
+
|
1158
|
+
protected
|
1159
|
+
|
1160
|
+
#
|
1161
|
+
# Triggers the job (calls the block)
|
1162
|
+
#
|
1163
|
+
def do_trigger
|
1164
|
+
|
1165
|
+
@block.call @job_id, @at
|
1166
|
+
|
1167
|
+
@scheduler.instance_variable_get(:@non_cron_jobs).delete @job_id
|
1168
|
+
end
|
1196
1169
|
end
|
1197
1170
|
|
1198
1171
|
#
|
@@ -1208,6 +1181,48 @@ module Rufus
|
|
1208
1181
|
|
1209
1182
|
@params[:every]
|
1210
1183
|
end
|
1184
|
+
|
1185
|
+
protected
|
1186
|
+
|
1187
|
+
#
|
1188
|
+
# triggers the job, then reschedules it if necessary
|
1189
|
+
#
|
1190
|
+
def do_trigger
|
1191
|
+
|
1192
|
+
hit_exception = false
|
1193
|
+
|
1194
|
+
begin
|
1195
|
+
|
1196
|
+
@block.call @job_id, @at, @params
|
1197
|
+
|
1198
|
+
rescue Exception => e
|
1199
|
+
|
1200
|
+
@scheduler.send(:log_exception, e)
|
1201
|
+
|
1202
|
+
hit_exception = true
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
if \
|
1206
|
+
@scheduler.instance_variable_get(:@exit_when_no_more_jobs) or
|
1207
|
+
(@params[:dont_reschedule] == true) or
|
1208
|
+
(hit_exception and @params[:try_again] == false)
|
1209
|
+
|
1210
|
+
@scheduler.instance_variable_get(:@non_cron_jobs).delete(job_id)
|
1211
|
+
# maybe it'd be better to wipe that reference from here anyway...
|
1212
|
+
|
1213
|
+
return
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
#
|
1217
|
+
# ok, reschedule ...
|
1218
|
+
|
1219
|
+
|
1220
|
+
params[:job] = self
|
1221
|
+
|
1222
|
+
@at = @at + Rufus.duration_to_f(params[:every])
|
1223
|
+
|
1224
|
+
@scheduler.send(:do_schedule_at, @at, params)
|
1225
|
+
end
|
1211
1226
|
end
|
1212
1227
|
|
1213
1228
|
#
|
@@ -1252,14 +1267,6 @@ module Rufus
|
|
1252
1267
|
@cron_line.matches?(time)
|
1253
1268
|
end
|
1254
1269
|
|
1255
|
-
#
|
1256
|
-
# As the name implies.
|
1257
|
-
#
|
1258
|
-
def trigger
|
1259
|
-
|
1260
|
-
@block.call @job_id, @cron_line, @params
|
1261
|
-
end
|
1262
|
-
|
1263
1270
|
#
|
1264
1271
|
# Returns the original cron tab string used to schedule this
|
1265
1272
|
# Job. Like for example "60/3 * * * Sun".
|
@@ -1280,275 +1287,15 @@ module Rufus
|
|
1280
1287
|
|
1281
1288
|
@cron_line.next_time(from)
|
1282
1289
|
end
|
1283
|
-
end
|
1284
|
-
|
1285
|
-
#
|
1286
|
-
# A 'cron line' is a line in the sense of a crontab
|
1287
|
-
# (man 5 crontab) file line.
|
1288
|
-
#
|
1289
|
-
class CronLine
|
1290
|
-
|
1291
|
-
#
|
1292
|
-
# The string used for creating this cronline instance.
|
1293
|
-
#
|
1294
|
-
attr_reader :original
|
1295
|
-
|
1296
|
-
attr_reader \
|
1297
|
-
:seconds,
|
1298
|
-
:minutes,
|
1299
|
-
:hours,
|
1300
|
-
:days,
|
1301
|
-
:months,
|
1302
|
-
:weekdays
|
1303
|
-
|
1304
|
-
def initialize (line)
|
1305
|
-
|
1306
|
-
super()
|
1307
|
-
|
1308
|
-
@original = line
|
1309
|
-
|
1310
|
-
items = line.split
|
1311
|
-
|
1312
|
-
unless [ 5, 6 ].include?(items.length)
|
1313
|
-
raise \
|
1314
|
-
"cron '#{line}' string should hold 5 or 6 items, " +
|
1315
|
-
"not #{items.length}" \
|
1316
|
-
end
|
1317
|
-
|
1318
|
-
offset = items.length - 5
|
1319
|
-
|
1320
|
-
@seconds = if offset == 1
|
1321
|
-
parse_item(items[0], 0, 59)
|
1322
|
-
else
|
1323
|
-
[ 0 ]
|
1324
|
-
end
|
1325
|
-
@minutes = parse_item(items[0+offset], 0, 59)
|
1326
|
-
@hours = parse_item(items[1+offset], 0, 24)
|
1327
|
-
@days = parse_item(items[2+offset], 1, 31)
|
1328
|
-
@months = parse_item(items[3+offset], 1, 12)
|
1329
|
-
@weekdays = parse_weekdays(items[4+offset])
|
1330
|
-
|
1331
|
-
#adjust_arrays()
|
1332
|
-
end
|
1333
|
-
|
1334
|
-
#
|
1335
|
-
# Returns true if the given time matches this cron line.
|
1336
|
-
#
|
1337
|
-
# (the precision is passed as well to determine if it's
|
1338
|
-
# worth checking seconds and minutes)
|
1339
|
-
#
|
1340
|
-
def matches? (time)
|
1341
|
-
#def matches? (time, precision)
|
1342
|
-
|
1343
|
-
time = Time.at(time) unless time.kind_of?(Time)
|
1344
|
-
|
1345
|
-
return false \
|
1346
|
-
if no_match?(time.sec, @seconds)
|
1347
|
-
#if precision <= 1 and no_match?(time.sec, @seconds)
|
1348
|
-
return false \
|
1349
|
-
if no_match?(time.min, @minutes)
|
1350
|
-
#if precision <= 60 and no_match?(time.min, @minutes)
|
1351
|
-
return false \
|
1352
|
-
if no_match?(time.hour, @hours)
|
1353
|
-
return false \
|
1354
|
-
if no_match?(time.day, @days)
|
1355
|
-
return false \
|
1356
|
-
if no_match?(time.month, @months)
|
1357
|
-
return false \
|
1358
|
-
if no_match?(time.wday, @weekdays)
|
1359
|
-
|
1360
|
-
true
|
1361
|
-
end
|
1362
|
-
|
1363
|
-
#
|
1364
|
-
# Returns an array of 6 arrays (seconds, minutes, hours, days,
|
1365
|
-
# months, weekdays).
|
1366
|
-
# This method is used by the cronline unit tests.
|
1367
|
-
#
|
1368
|
-
def to_array
|
1369
|
-
|
1370
|
-
[ @seconds, @minutes, @hours, @days, @months, @weekdays ]
|
1371
|
-
end
|
1372
|
-
|
1373
|
-
#
|
1374
|
-
# Returns the next time that this cron line is supposed to 'fire'
|
1375
|
-
#
|
1376
|
-
# This is raw, 3 secs to iterate over 1 year on my macbook :( brutal.
|
1377
|
-
#
|
1378
|
-
def next_time (now = Time.now)
|
1379
|
-
|
1380
|
-
#
|
1381
|
-
# position now to the next cron second
|
1382
1290
|
|
1383
|
-
|
1384
|
-
next_sec = @seconds.find { |s| s > now.sec } || 60 + @seconds.first
|
1385
|
-
now += next_sec - now.sec
|
1386
|
-
else
|
1387
|
-
now += 1
|
1388
|
-
end
|
1291
|
+
protected
|
1389
1292
|
|
1390
1293
|
#
|
1391
|
-
#
|
1392
|
-
|
1393
|
-
sjarray = nil
|
1394
|
-
|
1395
|
-
if @seconds
|
1396
|
-
|
1397
|
-
sjarray = []
|
1398
|
-
|
1399
|
-
i = @seconds.index(now.sec)
|
1400
|
-
ii = i
|
1401
|
-
|
1402
|
-
loop do
|
1403
|
-
cur = @seconds[ii]
|
1404
|
-
ii += 1
|
1405
|
-
ii = 0 if ii == @seconds.size
|
1406
|
-
nxt = @seconds[ii]
|
1407
|
-
nxt += 60 if ii == 0
|
1408
|
-
sjarray << (nxt - cur)
|
1409
|
-
break if ii == i
|
1410
|
-
end
|
1411
|
-
|
1412
|
-
else
|
1413
|
-
|
1414
|
-
sjarray = [ 1 ]
|
1415
|
-
end
|
1416
|
-
|
1294
|
+
# As the name implies.
|
1417
1295
|
#
|
1418
|
-
|
1419
|
-
|
1420
|
-
i = 0
|
1421
|
-
|
1422
|
-
loop do
|
1423
|
-
return now if matches?(now)
|
1424
|
-
now += sjarray[i]
|
1425
|
-
i += 1
|
1426
|
-
i = 0 if i == sjarray.size
|
1427
|
-
# danger... potentially no exit...
|
1428
|
-
end
|
1429
|
-
|
1430
|
-
nil
|
1431
|
-
end
|
1432
|
-
|
1433
|
-
private
|
1434
|
-
|
1435
|
-
#--
|
1436
|
-
# adjust values to Ruby
|
1437
|
-
#
|
1438
|
-
#def adjust_arrays()
|
1439
|
-
# @hours = @hours.collect { |h|
|
1440
|
-
# if h == 24
|
1441
|
-
# 0
|
1442
|
-
# else
|
1443
|
-
# h
|
1444
|
-
# end
|
1445
|
-
# } if @hours
|
1446
|
-
# @weekdays = @weekdays.collect { |wd|
|
1447
|
-
# wd - 1
|
1448
|
-
# } if @weekdays
|
1449
|
-
#end
|
1450
|
-
#
|
1451
|
-
# dead code, keeping it as a reminder
|
1452
|
-
#++
|
1453
|
-
|
1454
|
-
WDS = [ "sun", "mon", "tue", "wed", "thu", "fri", "sat" ]
|
1455
|
-
#
|
1456
|
-
# used by parse_weekday()
|
1457
|
-
|
1458
|
-
def parse_weekdays (item)
|
1459
|
-
|
1460
|
-
item = item.downcase
|
1461
|
-
|
1462
|
-
WDS.each_with_index do |day, index|
|
1463
|
-
item = item.gsub day, "#{index}"
|
1464
|
-
end
|
1465
|
-
|
1466
|
-
r = parse_item item, 0, 7
|
1467
|
-
|
1468
|
-
return r unless r.is_a?(Array)
|
1469
|
-
|
1470
|
-
r.collect { |e| e == 7 ? 0 : e }.uniq
|
1471
|
-
end
|
1472
|
-
|
1473
|
-
def parse_item (item, min, max)
|
1474
|
-
|
1475
|
-
return nil \
|
1476
|
-
if item == "*"
|
1477
|
-
return parse_list(item, min, max) \
|
1478
|
-
if item.index(",")
|
1479
|
-
return parse_range(item, min, max) \
|
1480
|
-
if item.index("*") or item.index("-")
|
1481
|
-
|
1482
|
-
i = Integer(item)
|
1483
|
-
|
1484
|
-
i = min if i < min
|
1485
|
-
i = max if i > max
|
1486
|
-
|
1487
|
-
[ i ]
|
1488
|
-
end
|
1489
|
-
|
1490
|
-
def parse_list (item, min, max)
|
1491
|
-
|
1492
|
-
items = item.split(",")
|
1493
|
-
|
1494
|
-
items.inject([]) { |r, i| r.push(parse_range(i, min, max)) }.flatten
|
1495
|
-
end
|
1496
|
-
|
1497
|
-
def parse_range (item, min, max)
|
1498
|
-
|
1499
|
-
i = item.index("-")
|
1500
|
-
j = item.index("/")
|
1501
|
-
|
1502
|
-
return item.to_i if (not i and not j)
|
1503
|
-
|
1504
|
-
inc = 1
|
1505
|
-
|
1506
|
-
inc = Integer(item[j+1..-1]) if j
|
1507
|
-
|
1508
|
-
istart = -1
|
1509
|
-
iend = -1
|
1510
|
-
|
1511
|
-
if i
|
1512
|
-
|
1513
|
-
istart = Integer(item[0..i-1])
|
1514
|
-
|
1515
|
-
if j
|
1516
|
-
iend = Integer(item[i+1..j])
|
1517
|
-
else
|
1518
|
-
iend = Integer(item[i+1..-1])
|
1519
|
-
end
|
1520
|
-
|
1521
|
-
else # case */x
|
1522
|
-
|
1523
|
-
istart = min
|
1524
|
-
iend = max
|
1525
|
-
end
|
1526
|
-
|
1527
|
-
istart = min if istart < min
|
1528
|
-
iend = max if iend > max
|
1529
|
-
|
1530
|
-
result = []
|
1531
|
-
|
1532
|
-
value = istart
|
1533
|
-
loop do
|
1534
|
-
|
1535
|
-
result << value
|
1536
|
-
value = value + inc
|
1537
|
-
break if value > iend
|
1538
|
-
end
|
1539
|
-
|
1540
|
-
result
|
1541
|
-
end
|
1542
|
-
|
1543
|
-
def no_match? (value, cron_values)
|
1544
|
-
|
1545
|
-
return false if not cron_values
|
1546
|
-
|
1547
|
-
cron_values.each do |v|
|
1548
|
-
return false if value == v # ok, it matches
|
1549
|
-
end
|
1296
|
+
def do_trigger
|
1550
1297
|
|
1551
|
-
|
1298
|
+
@block.call @job_id, @cron_line, @params
|
1552
1299
|
end
|
1553
1300
|
end
|
1554
1301
|
|