rufus-scheduler 3.0.8 → 3.2.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 +75 -0
- data/CREDITS.txt +21 -0
- data/LICENSE.txt +1 -1
- data/README.md +120 -15
- data/lib/rufus/scheduler/cronline.rb +107 -100
- data/lib/rufus/scheduler/job_array.rb +2 -1
- data/lib/rufus/scheduler/jobs.rb +53 -41
- data/lib/rufus/scheduler/locks.rb +95 -0
- data/lib/rufus/scheduler/util.rb +8 -33
- data/lib/rufus/scheduler/zones.rb +175 -0
- data/lib/rufus/scheduler/zotime.rb +167 -0
- data/lib/rufus/scheduler.rb +67 -67
- data/rufus-scheduler.gemspec +3 -28
- metadata +22 -47
- data/spec/basics_spec.rb +0 -49
- data/spec/cronline_spec.rb +0 -681
- data/spec/custom_locks_spec.rb +0 -47
- data/spec/error_spec.rb +0 -139
- data/spec/job_array_spec.rb +0 -39
- data/spec/job_at_spec.rb +0 -58
- data/spec/job_cron_spec.rb +0 -106
- data/spec/job_every_spec.rb +0 -90
- data/spec/job_in_spec.rb +0 -20
- data/spec/job_interval_spec.rb +0 -68
- data/spec/job_repeat_spec.rb +0 -356
- data/spec/job_spec.rb +0 -631
- data/spec/lockfile_spec.rb +0 -61
- data/spec/parse_spec.rb +0 -261
- data/spec/schedule_at_spec.rb +0 -158
- data/spec/schedule_cron_spec.rb +0 -66
- data/spec/schedule_every_spec.rb +0 -109
- data/spec/schedule_in_spec.rb +0 -80
- data/spec/schedule_interval_spec.rb +0 -128
- data/spec/scheduler_spec.rb +0 -1049
- data/spec/spec_helper.rb +0 -126
- data/spec/threads_spec.rb +0 -96
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2006-
|
|
2
|
+
# Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
|
|
3
3
|
#
|
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
# Made in Japan.
|
|
23
23
|
#++
|
|
24
24
|
|
|
25
|
+
require 'set'
|
|
26
|
+
|
|
25
27
|
|
|
26
28
|
class Rufus::Scheduler
|
|
27
29
|
|
|
@@ -40,13 +42,13 @@ class Rufus::Scheduler
|
|
|
40
42
|
attr_reader :hours
|
|
41
43
|
attr_reader :days
|
|
42
44
|
attr_reader :months
|
|
45
|
+
#attr_reader :monthdays # reader defined below
|
|
43
46
|
attr_reader :weekdays
|
|
44
|
-
attr_reader :monthdays
|
|
45
47
|
attr_reader :timezone
|
|
46
48
|
|
|
47
49
|
def initialize(line)
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
fail ArgumentError.new(
|
|
50
52
|
"not a string: #{line.inspect}"
|
|
51
53
|
) unless line.is_a?(String)
|
|
52
54
|
|
|
@@ -54,10 +56,9 @@ class Rufus::Scheduler
|
|
|
54
56
|
|
|
55
57
|
items = line.split
|
|
56
58
|
|
|
57
|
-
@timezone =
|
|
58
|
-
items.pop if @timezone
|
|
59
|
+
@timezone = items.pop if ZoTime.is_timezone?(items.last)
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
fail ArgumentError.new(
|
|
61
62
|
"not a valid cronline : '#{line}'"
|
|
62
63
|
) unless items.length == 5 or items.length == 6
|
|
63
64
|
|
|
@@ -72,7 +73,7 @@ class Rufus::Scheduler
|
|
|
72
73
|
|
|
73
74
|
[ @seconds, @minutes, @hours, @months ].each do |es|
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
fail ArgumentError.new(
|
|
76
77
|
"invalid cronline: '#{line}'"
|
|
77
78
|
) if es && es.find { |e| ! e.is_a?(Fixnum) }
|
|
78
79
|
end
|
|
@@ -82,9 +83,7 @@ class Rufus::Scheduler
|
|
|
82
83
|
#
|
|
83
84
|
def matches?(time)
|
|
84
85
|
|
|
85
|
-
time =
|
|
86
|
-
|
|
87
|
-
time = @timezone.utc_to_local(time.getutc) if @timezone
|
|
86
|
+
time = ZoTime.new(time.to_f, @timezone || ENV['TZ']).time
|
|
88
87
|
|
|
89
88
|
return false unless sub_match?(time, :sec, @seconds)
|
|
90
89
|
return false unless sub_match?(time, :min, @minutes)
|
|
@@ -122,37 +121,34 @@ class Rufus::Scheduler
|
|
|
122
121
|
#
|
|
123
122
|
def next_time(from=Time.now)
|
|
124
123
|
|
|
125
|
-
time =
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
# start at the next second
|
|
129
|
-
time = time + 1
|
|
124
|
+
time = nil
|
|
125
|
+
zotime = ZoTime.new(from.to_i + 1, @timezone || ENV['TZ'])
|
|
130
126
|
|
|
131
127
|
loop do
|
|
128
|
+
|
|
129
|
+
time = zotime.time
|
|
130
|
+
|
|
132
131
|
unless date_match?(time)
|
|
133
|
-
|
|
134
|
-
time += (24 - time.hour) * 3600 - time.min * 60 - time.sec
|
|
135
|
-
time -= 3600 if time.isdst != dst # not necessary for winter, but...
|
|
132
|
+
zotime.add((24 - time.hour) * 3600 - time.min * 60 - time.sec)
|
|
136
133
|
next
|
|
137
134
|
end
|
|
138
135
|
unless sub_match?(time, :hour, @hours)
|
|
139
|
-
|
|
136
|
+
zotime.add((60 - time.min) * 60 - time.sec)
|
|
137
|
+
next
|
|
140
138
|
end
|
|
141
139
|
unless sub_match?(time, :min, @minutes)
|
|
142
|
-
|
|
140
|
+
zotime.add(60 - time.sec)
|
|
141
|
+
next
|
|
143
142
|
end
|
|
144
143
|
unless sub_match?(time, :sec, @seconds)
|
|
145
|
-
time
|
|
144
|
+
zotime.add(next_second(time))
|
|
145
|
+
next
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
break
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
rescue TZInfo::PeriodNotFound
|
|
154
|
-
|
|
155
|
-
next_time(from + 3600)
|
|
151
|
+
time
|
|
156
152
|
end
|
|
157
153
|
|
|
158
154
|
# Returns the previous time the cronline matched. It's like next_time, but
|
|
@@ -160,34 +156,34 @@ class Rufus::Scheduler
|
|
|
160
156
|
#
|
|
161
157
|
def previous_time(from=Time.now)
|
|
162
158
|
|
|
163
|
-
time =
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# start at the previous second
|
|
167
|
-
time = time - 1
|
|
159
|
+
time = nil
|
|
160
|
+
zotime = ZoTime.new(from.to_i - 1, @timezone || ENV['TZ'])
|
|
168
161
|
|
|
169
162
|
loop do
|
|
163
|
+
|
|
164
|
+
time = zotime.time
|
|
165
|
+
|
|
170
166
|
unless date_match?(time)
|
|
171
|
-
time
|
|
167
|
+
zotime.substract(time.hour * 3600 + time.min * 60 + time.sec + 1)
|
|
168
|
+
next
|
|
172
169
|
end
|
|
173
170
|
unless sub_match?(time, :hour, @hours)
|
|
174
|
-
time
|
|
171
|
+
zotime.substract(time.min * 60 + time.sec + 1)
|
|
172
|
+
next
|
|
175
173
|
end
|
|
176
174
|
unless sub_match?(time, :min, @minutes)
|
|
177
|
-
time
|
|
175
|
+
zotime.substract(time.sec + 1)
|
|
176
|
+
next
|
|
178
177
|
end
|
|
179
178
|
unless sub_match?(time, :sec, @seconds)
|
|
180
|
-
time
|
|
179
|
+
zotime.substract(prev_second(time))
|
|
180
|
+
next
|
|
181
181
|
end
|
|
182
182
|
|
|
183
183
|
break
|
|
184
184
|
end
|
|
185
185
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
rescue TZInfo::PeriodNotFound
|
|
189
|
-
|
|
190
|
-
previous_time(time)
|
|
186
|
+
time
|
|
191
187
|
end
|
|
192
188
|
|
|
193
189
|
# Returns an array of 6 arrays (seconds, minutes, hours, days,
|
|
@@ -197,14 +193,14 @@ class Rufus::Scheduler
|
|
|
197
193
|
def to_array
|
|
198
194
|
|
|
199
195
|
[
|
|
200
|
-
@seconds,
|
|
201
|
-
@minutes,
|
|
202
|
-
@hours,
|
|
203
|
-
@days,
|
|
204
|
-
@months,
|
|
205
|
-
@weekdays,
|
|
206
|
-
@monthdays,
|
|
207
|
-
@timezone
|
|
196
|
+
toa(@seconds),
|
|
197
|
+
toa(@minutes),
|
|
198
|
+
toa(@hours),
|
|
199
|
+
toa(@days),
|
|
200
|
+
toa(@months),
|
|
201
|
+
toa(@weekdays),
|
|
202
|
+
toa(@monthdays),
|
|
203
|
+
@timezone
|
|
208
204
|
]
|
|
209
205
|
end
|
|
210
206
|
|
|
@@ -212,24 +208,25 @@ class Rufus::Scheduler
|
|
|
212
208
|
# cron line.
|
|
213
209
|
#
|
|
214
210
|
# #brute_frequency, on the other hand, will compute the frequency by
|
|
215
|
-
# examining a whole, that can take more than seconds for a seconds
|
|
211
|
+
# examining a whole year, that can take more than seconds for a seconds
|
|
216
212
|
# level cron...
|
|
217
213
|
#
|
|
218
214
|
def frequency
|
|
219
215
|
|
|
220
216
|
return brute_frequency unless @seconds && @seconds.length > 1
|
|
221
217
|
|
|
222
|
-
|
|
223
|
-
prev = @seconds[0]
|
|
218
|
+
secs = toa(@seconds)
|
|
224
219
|
|
|
225
|
-
|
|
220
|
+
secs[1..-1].inject([ secs[0], 60 ]) { |(prev, delta), sec|
|
|
226
221
|
d = sec - prev
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
delta
|
|
222
|
+
[ sec, d < delta ? d : delta ]
|
|
223
|
+
}[1]
|
|
231
224
|
end
|
|
232
225
|
|
|
226
|
+
# Caching facility. Currently only used for brute frequencies.
|
|
227
|
+
#
|
|
228
|
+
@cache = {}; class << self; attr_reader :cache; end
|
|
229
|
+
|
|
233
230
|
# Returns the shortest delta between two potential occurences of the
|
|
234
231
|
# schedule described by this cronline.
|
|
235
232
|
#
|
|
@@ -246,16 +243,13 @@ class Rufus::Scheduler
|
|
|
246
243
|
# Of course, this method can get VERY slow if you call on it a second-
|
|
247
244
|
# based cronline...
|
|
248
245
|
#
|
|
249
|
-
# Since it's a rarely used method, I haven't taken the time to make it
|
|
250
|
-
# smarter/faster.
|
|
251
|
-
#
|
|
252
|
-
# One obvious improvement would be to cache the result once computed...
|
|
253
|
-
#
|
|
254
|
-
# See https://github.com/jmettraux/rufus-scheduler/issues/89
|
|
255
|
-
# for a discussion about this method.
|
|
256
|
-
#
|
|
257
246
|
def brute_frequency
|
|
258
247
|
|
|
248
|
+
key = "brute_frequency:#{@original}"
|
|
249
|
+
|
|
250
|
+
delta = self.class.cache[key]
|
|
251
|
+
return delta if delta
|
|
252
|
+
|
|
259
253
|
delta = 366 * DAY_S
|
|
260
254
|
|
|
261
255
|
t0 = previous_time(Time.local(2000, 1, 1))
|
|
@@ -270,16 +264,53 @@ class Rufus::Scheduler
|
|
|
270
264
|
delta = d if d < delta
|
|
271
265
|
|
|
272
266
|
break if @months == nil && t1.month == 2
|
|
273
|
-
break if t1.year
|
|
267
|
+
break if t1.year >= 2001
|
|
274
268
|
|
|
275
269
|
t0 = t1
|
|
276
270
|
end
|
|
277
271
|
|
|
278
|
-
delta
|
|
272
|
+
self.class.cache[key] = delta
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def next_second(time)
|
|
276
|
+
|
|
277
|
+
secs = toa(@seconds)
|
|
278
|
+
|
|
279
|
+
return secs.first + 60 - time.sec if time.sec > secs.last
|
|
280
|
+
|
|
281
|
+
secs.shift while secs.first < time.sec
|
|
282
|
+
|
|
283
|
+
secs.first - time.sec
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def prev_second(time)
|
|
287
|
+
|
|
288
|
+
secs = toa(@seconds)
|
|
289
|
+
|
|
290
|
+
return time.sec + 60 - secs.last if time.sec < secs.first
|
|
291
|
+
|
|
292
|
+
secs.pop while time.sec < secs.last
|
|
293
|
+
|
|
294
|
+
time.sec - secs.last
|
|
279
295
|
end
|
|
280
296
|
|
|
281
297
|
protected
|
|
282
298
|
|
|
299
|
+
def sc_sort(a)
|
|
300
|
+
|
|
301
|
+
a.sort_by { |e| e.is_a?(String) ? 61 : e.to_i }
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
if RUBY_VERSION >= '1.9'
|
|
305
|
+
def toa(item)
|
|
306
|
+
item == nil ? nil : item.to_a
|
|
307
|
+
end
|
|
308
|
+
else
|
|
309
|
+
def toa(item)
|
|
310
|
+
item.is_a?(Set) ? sc_sort(item.to_a) : item
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
283
314
|
WEEKDAYS = %w[ sun mon tue wed thu fri sat ]
|
|
284
315
|
DAY_S = 24 * 3600
|
|
285
316
|
WEEK_S = 7 * DAY_S
|
|
@@ -297,7 +328,7 @@ class Rufus::Scheduler
|
|
|
297
328
|
|
|
298
329
|
if m = it.match(/^(.+)#(l|-?[12345])$/)
|
|
299
330
|
|
|
300
|
-
|
|
331
|
+
fail ArgumentError.new(
|
|
301
332
|
"ranges are not supported for monthdays (#{it})"
|
|
302
333
|
) if m[1].index('-')
|
|
303
334
|
|
|
@@ -310,7 +341,7 @@ class Rufus::Scheduler
|
|
|
310
341
|
expr = it.dup
|
|
311
342
|
WEEKDAYS.each_with_index { |a, i| expr.gsub!(/#{a}/, i.to_s) }
|
|
312
343
|
|
|
313
|
-
|
|
344
|
+
fail ArgumentError.new(
|
|
314
345
|
"invalid weekday expression (#{it})"
|
|
315
346
|
) if expr !~ /^0*[0-7](-0*[0-7])?$/
|
|
316
347
|
|
|
@@ -321,7 +352,7 @@ class Rufus::Scheduler
|
|
|
321
352
|
end
|
|
322
353
|
end
|
|
323
354
|
|
|
324
|
-
weekdays = weekdays.uniq if weekdays
|
|
355
|
+
weekdays = weekdays.uniq.sort if weekdays
|
|
325
356
|
|
|
326
357
|
[ weekdays, monthdays ]
|
|
327
358
|
end
|
|
@@ -332,11 +363,13 @@ class Rufus::Scheduler
|
|
|
332
363
|
|
|
333
364
|
r = item.split(',').map { |i| parse_range(i.strip, min, max) }.flatten
|
|
334
365
|
|
|
335
|
-
|
|
366
|
+
fail ArgumentError.new(
|
|
336
367
|
"found duplicates in #{item.inspect}"
|
|
337
368
|
) if r.uniq.size < r.size
|
|
338
369
|
|
|
339
|
-
r
|
|
370
|
+
r = sc_sort(r)
|
|
371
|
+
|
|
372
|
+
Set.new(r)
|
|
340
373
|
end
|
|
341
374
|
|
|
342
375
|
RANGE_REGEX = /^(\*|\d{1,2})(?:-(\d{1,2}))?(?:\/(\d{1,2}))?$/
|
|
@@ -345,11 +378,11 @@ class Rufus::Scheduler
|
|
|
345
378
|
|
|
346
379
|
return %w[ L ] if item == 'L'
|
|
347
380
|
|
|
348
|
-
item = '*' + item if item
|
|
381
|
+
item = '*' + item if item[0, 1] == '/'
|
|
349
382
|
|
|
350
383
|
m = item.match(RANGE_REGEX)
|
|
351
384
|
|
|
352
|
-
|
|
385
|
+
fail ArgumentError.new(
|
|
353
386
|
"cannot parse #{item.inspect}"
|
|
354
387
|
) unless m
|
|
355
388
|
|
|
@@ -363,7 +396,7 @@ class Rufus::Scheduler
|
|
|
363
396
|
inc = m[3]
|
|
364
397
|
inc = inc ? inc.to_i : 1
|
|
365
398
|
|
|
366
|
-
|
|
399
|
+
fail ArgumentError.new(
|
|
367
400
|
"#{item.inspect} is not in range #{min}..#{max}"
|
|
368
401
|
) if sta < min || edn > max
|
|
369
402
|
|
|
@@ -435,32 +468,6 @@ class Rufus::Scheduler
|
|
|
435
468
|
|
|
436
469
|
[ "#{WEEKDAYS[date.wday]}##{pos}", "#{WEEKDAYS[date.wday]}##{neg}" ]
|
|
437
470
|
end
|
|
438
|
-
|
|
439
|
-
def local_time(time)
|
|
440
|
-
|
|
441
|
-
@timezone ? @timezone.utc_to_local(time.getutc) : time
|
|
442
|
-
end
|
|
443
|
-
|
|
444
|
-
def global_time(time, from_in_utc)
|
|
445
|
-
|
|
446
|
-
if @timezone
|
|
447
|
-
time =
|
|
448
|
-
begin
|
|
449
|
-
@timezone.local_to_utc(time)
|
|
450
|
-
rescue TZInfo::AmbiguousTime
|
|
451
|
-
@timezone.local_to_utc(time, time.isdst)
|
|
452
|
-
end
|
|
453
|
-
time = time.getlocal unless from_in_utc
|
|
454
|
-
end
|
|
455
|
-
|
|
456
|
-
time
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
def round_to_seconds(time)
|
|
460
|
-
|
|
461
|
-
# Ruby 1.8 doesn't have #round
|
|
462
|
-
time.respond_to?(:round) ? time.round : time - time.usec * 1e-6
|
|
463
|
-
end
|
|
464
471
|
end
|
|
465
472
|
end
|
|
466
473
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2006-
|
|
2
|
+
# Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
|
|
3
3
|
#
|
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
# Made in Japan.
|
|
23
23
|
#++
|
|
24
24
|
|
|
25
|
+
|
|
25
26
|
module Rufus
|
|
26
27
|
|
|
27
28
|
class Scheduler
|
data/lib/rufus/scheduler/jobs.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2006-
|
|
2
|
+
# Copyright (c) 2006-2015, John Mettraux, jmettraux@gmail.com
|
|
3
3
|
#
|
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
# of this software and associated documentation files (the "Software"), to deal
|
|
@@ -91,7 +91,7 @@ module Rufus
|
|
|
91
91
|
|
|
92
92
|
@id = determine_id
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
fail(
|
|
95
95
|
ArgumentError,
|
|
96
96
|
'missing block or callable to schedule',
|
|
97
97
|
caller[2..-1]
|
|
@@ -117,15 +117,16 @@ module Rufus
|
|
|
117
117
|
|
|
118
118
|
def trigger(time)
|
|
119
119
|
|
|
120
|
-
set_next_time(
|
|
120
|
+
set_next_time(time)
|
|
121
121
|
|
|
122
|
-
return if
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
return if (
|
|
123
|
+
opts[:overlap] == false &&
|
|
124
|
+
running?
|
|
125
|
+
)
|
|
126
|
+
return if (
|
|
125
127
|
callback(:confirm_lock, time) &&
|
|
126
128
|
callback(:on_pre_trigger, time)
|
|
127
|
-
|
|
128
|
-
return if r == false
|
|
129
|
+
) == false
|
|
129
130
|
|
|
130
131
|
@count += 1
|
|
131
132
|
|
|
@@ -234,7 +235,7 @@ module Rufus
|
|
|
234
235
|
|
|
235
236
|
rescue StandardError => se
|
|
236
237
|
|
|
237
|
-
|
|
238
|
+
fail se unless do_rescue
|
|
238
239
|
|
|
239
240
|
return if se.is_a?(KillSignal) # discard
|
|
240
241
|
|
|
@@ -272,7 +273,7 @@ module Rufus
|
|
|
272
273
|
|
|
273
274
|
def post_trigger(time)
|
|
274
275
|
|
|
275
|
-
set_next_time(
|
|
276
|
+
set_next_time(time, true)
|
|
276
277
|
|
|
277
278
|
callback(:on_post_trigger, time)
|
|
278
279
|
end
|
|
@@ -283,7 +284,7 @@ module Rufus
|
|
|
283
284
|
Thread.new do
|
|
284
285
|
|
|
285
286
|
Thread.current[@scheduler.thread_key] = true
|
|
286
|
-
Thread.current[:
|
|
287
|
+
Thread.current[:rufus_scheduler_work_thread] = true
|
|
287
288
|
|
|
288
289
|
loop do
|
|
289
290
|
|
|
@@ -339,7 +340,7 @@ module Rufus
|
|
|
339
340
|
|
|
340
341
|
def occurrences(time0, time1)
|
|
341
342
|
|
|
342
|
-
time >= time0 && time <= time1 ? [ time ] : []
|
|
343
|
+
(time >= time0 && time <= time1) ? [ time ] : []
|
|
343
344
|
end
|
|
344
345
|
|
|
345
346
|
protected
|
|
@@ -350,13 +351,13 @@ module Rufus
|
|
|
350
351
|
self.class.name.split(':').last.downcase[0..-4],
|
|
351
352
|
@scheduled_at.to_f,
|
|
352
353
|
@next_time.to_f,
|
|
353
|
-
|
|
354
|
+
self.hash.abs
|
|
354
355
|
].map(&:to_s).join('_')
|
|
355
356
|
end
|
|
356
357
|
|
|
357
358
|
# There is no next_time for one time jobs, hence the false.
|
|
358
359
|
#
|
|
359
|
-
def set_next_time(
|
|
360
|
+
def set_next_time(trigger_time, is_post=false)
|
|
360
361
|
|
|
361
362
|
@next_time = is_post ? nil : false
|
|
362
363
|
end
|
|
@@ -390,7 +391,7 @@ module Rufus
|
|
|
390
391
|
attr_reader :paused_at
|
|
391
392
|
|
|
392
393
|
attr_reader :first_at
|
|
393
|
-
|
|
394
|
+
attr_reader :last_at
|
|
394
395
|
attr_accessor :times
|
|
395
396
|
|
|
396
397
|
def initialize(scheduler, duration, opts, block)
|
|
@@ -401,47 +402,53 @@ module Rufus
|
|
|
401
402
|
|
|
402
403
|
@times = opts[:times]
|
|
403
404
|
|
|
404
|
-
|
|
405
|
+
fail ArgumentError.new(
|
|
405
406
|
"cannot accept :times => #{@times.inspect}, not nil or an int"
|
|
406
407
|
) unless @times == nil || @times.is_a?(Fixnum)
|
|
407
408
|
|
|
408
409
|
self.first_at =
|
|
409
410
|
opts[:first] || opts[:first_time] ||
|
|
410
411
|
opts[:first_at] || opts[:first_in] ||
|
|
411
|
-
|
|
412
|
+
nil
|
|
412
413
|
self.last_at =
|
|
413
414
|
opts[:last] || opts[:last_at] || opts[:last_in]
|
|
414
415
|
end
|
|
415
416
|
|
|
416
417
|
def first_at=(first)
|
|
417
418
|
|
|
418
|
-
|
|
419
|
-
|
|
419
|
+
return (@first_at = nil) if first == nil
|
|
420
|
+
|
|
421
|
+
n0 = Time.now
|
|
422
|
+
n1 = n0 + 0.003
|
|
423
|
+
|
|
424
|
+
first = n0 if first == :now || first == :immediately || first == 0
|
|
420
425
|
|
|
421
426
|
@first_at = Rufus::Scheduler.parse_to_time(first)
|
|
427
|
+
@first_at = n1 if @first_at >= n0 && @first_at < n1
|
|
422
428
|
|
|
423
|
-
|
|
429
|
+
fail ArgumentError.new(
|
|
424
430
|
"cannot set first[_at|_in] in the past: " +
|
|
425
431
|
"#{first.inspect} -> #{@first_at.inspect}"
|
|
426
|
-
) if
|
|
432
|
+
) if @first_at < n0
|
|
433
|
+
|
|
434
|
+
@first_at
|
|
427
435
|
end
|
|
428
436
|
|
|
429
437
|
def last_at=(last)
|
|
430
438
|
|
|
431
439
|
@last_at = last ? Rufus::Scheduler.parse_to_time(last) : nil
|
|
432
440
|
|
|
433
|
-
|
|
441
|
+
fail ArgumentError.new(
|
|
434
442
|
"cannot set last[_at|_in] in the past: " +
|
|
435
443
|
"#{last.inspect} -> #{@last_at.inspect}"
|
|
436
444
|
) if last && @last_at < Time.now
|
|
445
|
+
|
|
446
|
+
@last_at
|
|
437
447
|
end
|
|
438
448
|
|
|
439
449
|
def trigger(time)
|
|
440
450
|
|
|
441
451
|
return if @paused_at
|
|
442
|
-
return if time < @first_at
|
|
443
|
-
#
|
|
444
|
-
# TODO: remove me when @first_at gets reworked
|
|
445
452
|
|
|
446
453
|
return (@next_time = nil) if @times && @times < 1
|
|
447
454
|
return (@next_time = nil) if @last_at && time >= @last_at
|
|
@@ -473,7 +480,7 @@ module Rufus
|
|
|
473
480
|
[
|
|
474
481
|
self.class.name.split(':').last.downcase[0..-4],
|
|
475
482
|
@scheduled_at.to_f,
|
|
476
|
-
|
|
483
|
+
self.hash.abs
|
|
477
484
|
].map(&:to_s).join('_')
|
|
478
485
|
end
|
|
479
486
|
|
|
@@ -522,25 +529,26 @@ module Rufus
|
|
|
522
529
|
|
|
523
530
|
@frequency = Rufus::Scheduler.parse_in(@original)
|
|
524
531
|
|
|
525
|
-
|
|
532
|
+
fail ArgumentError.new(
|
|
526
533
|
"cannot schedule #{self.class} with a frequency " +
|
|
527
534
|
"of #{@frequency.inspect} (#{@original.inspect})"
|
|
528
535
|
) if @frequency <= 0
|
|
529
536
|
|
|
530
|
-
set_next_time(
|
|
537
|
+
set_next_time(nil)
|
|
531
538
|
end
|
|
532
539
|
|
|
533
540
|
protected
|
|
534
541
|
|
|
535
|
-
def set_next_time(
|
|
542
|
+
def set_next_time(trigger_time, is_post=false)
|
|
536
543
|
|
|
537
544
|
return if is_post
|
|
538
545
|
|
|
546
|
+
n = Time.now
|
|
547
|
+
|
|
539
548
|
@next_time =
|
|
540
|
-
if
|
|
541
|
-
trigger_time + @frequency
|
|
542
|
-
|
|
543
|
-
Time.now + @frequency
|
|
549
|
+
if @first_at == nil || @first_at < n
|
|
550
|
+
nt = (@next_time || trigger_time || n) + @frequency
|
|
551
|
+
nt > n ? nt : (trigger_time || n) + @frequency
|
|
544
552
|
else
|
|
545
553
|
@first_at
|
|
546
554
|
end
|
|
@@ -562,23 +570,23 @@ module Rufus
|
|
|
562
570
|
|
|
563
571
|
@interval = Rufus::Scheduler.parse_in(@original)
|
|
564
572
|
|
|
565
|
-
|
|
573
|
+
fail ArgumentError.new(
|
|
566
574
|
"cannot schedule #{self.class} with an interval " +
|
|
567
575
|
"of #{@interval.inspect} (#{@original.inspect})"
|
|
568
576
|
) if @interval <= 0
|
|
569
577
|
|
|
570
|
-
set_next_time(
|
|
578
|
+
set_next_time(nil)
|
|
571
579
|
end
|
|
572
580
|
|
|
573
581
|
protected
|
|
574
582
|
|
|
575
|
-
def set_next_time(
|
|
583
|
+
def set_next_time(trigger_time, is_post=false)
|
|
576
584
|
|
|
577
585
|
@next_time =
|
|
578
586
|
if is_post
|
|
579
587
|
Time.now + @interval
|
|
580
588
|
elsif trigger_time.nil?
|
|
581
|
-
if @first_at < Time.now
|
|
589
|
+
if @first_at == nil || @first_at < Time.now
|
|
582
590
|
Time.now + @interval
|
|
583
591
|
else
|
|
584
592
|
@first_at
|
|
@@ -601,7 +609,7 @@ module Rufus
|
|
|
601
609
|
super(scheduler, cronline, opts, block)
|
|
602
610
|
|
|
603
611
|
@cron_line = opts[:_t] || CronLine.new(cronline)
|
|
604
|
-
|
|
612
|
+
set_next_time(nil)
|
|
605
613
|
end
|
|
606
614
|
|
|
607
615
|
def frequency
|
|
@@ -616,14 +624,18 @@ module Rufus
|
|
|
616
624
|
|
|
617
625
|
protected
|
|
618
626
|
|
|
619
|
-
def set_next_time(
|
|
627
|
+
def set_next_time(trigger_time, is_post=false)
|
|
620
628
|
|
|
621
|
-
@next_time =
|
|
629
|
+
@next_time = next_time_from(trigger_time || Time.now)
|
|
622
630
|
end
|
|
623
631
|
|
|
624
632
|
def next_time_from(time)
|
|
625
633
|
|
|
626
|
-
@
|
|
634
|
+
if @first_at == nil || @first_at <= time
|
|
635
|
+
@cron_line.next_time(time)
|
|
636
|
+
else
|
|
637
|
+
@first_at
|
|
638
|
+
end
|
|
627
639
|
end
|
|
628
640
|
end
|
|
629
641
|
end
|