rufus-scheduler 3.1.1 → 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 +57 -0
- data/CREDITS.txt +15 -0
- data/README.md +48 -3
- data/lib/rufus/scheduler/cronline.rb +48 -45
- data/lib/rufus/scheduler/jobs.rb +28 -18
- data/lib/rufus/scheduler/util.rb +6 -8
- data/lib/rufus/scheduler/zones.rb +1 -0
- data/lib/rufus/scheduler/zotime.rb +22 -10
- data/lib/rufus/scheduler.rb +7 -7
- data/rufus-scheduler.gemspec +1 -1
- metadata +11 -36
- data/spec/basics_spec.rb +0 -54
- data/spec/cronline_spec.rb +0 -730
- 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 -128
- data/spec/job_every_spec.rb +0 -104
- data/spec/job_in_spec.rb +0 -20
- data/spec/job_interval_spec.rb +0 -68
- data/spec/job_repeat_spec.rb +0 -357
- data/spec/job_spec.rb +0 -631
- data/spec/lock_custom_spec.rb +0 -47
- data/spec/lock_flock_spec.rb +0 -47
- data/spec/lock_lockfile_spec.rb +0 -61
- data/spec/lock_spec.rb +0 -59
- data/spec/parse_spec.rb +0 -263
- 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 -1052
- data/spec/spec_helper.rb +0 -126
- data/spec/threads_spec.rb +0 -96
- data/spec/zotime_spec.rb +0 -396
data/CHANGELOG.txt
CHANGED
|
@@ -2,6 +2,63 @@
|
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
== rufus-scheduler - 3.2.0 released 2015-12-28
|
|
6
|
+
|
|
7
|
+
- cache CronLine#brute_frequency results, gh-188 and gh-89
|
|
8
|
+
- "every" shift prevention by https://github.com/Korrigan
|
|
9
|
+
- Ruby warnings silenced by https://github.com/vivitar
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
== rufus-scheduler - 3.1.10 released 2015-11-18
|
|
13
|
+
|
|
14
|
+
- allow for :first_in => 0, gh-179 by https://github.com/JonMcPherson
|
|
15
|
+
for https://github.com/Shopify/dashing/commit/ea3730fa4
|
|
16
|
+
- stop shipping specs in gem
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
== rufus-scheduler - 3.1.9 released 2015-11-12
|
|
20
|
+
|
|
21
|
+
- fix potential RuntimeError in CronLine#prev_second,
|
|
22
|
+
by Alexandru https://github.com/alexandru-calinoiu
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
== rufus-scheduler - 3.1.8 released 2015-11-10
|
|
26
|
+
|
|
27
|
+
- stop jumping eagerly out of DST, fix for one hour jump when leaving DST
|
|
28
|
+
thanks Alyssa http://github.com/alyssa
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
== rufus-scheduler - 3.1.7 released 2015-10-15
|
|
32
|
+
|
|
33
|
+
- ack #unscheduled_at in #scheduled?, by Claude https://github.com/claudeatsafe
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
== rufus-scheduler - 3.1.6 released 2015-10-01
|
|
37
|
+
|
|
38
|
+
- fix job id uniqueness (JRuby), thanks 김성식 https://github.com/kssminus
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
== rufus-scheduler - 3.1.5 released 2015-09-25
|
|
42
|
+
|
|
43
|
+
- fix for "not a valid cronline" on "mingw" Ruby distributions, gh-166
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
== rufus-scheduler - 3.1.4 released 2015/08/29
|
|
47
|
+
|
|
48
|
+
- fix cron issue reported by Jesse https://github.com/jhw-at-prosperworks-com
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
== rufus-scheduler - 3.1.3 released 2015/06/20
|
|
52
|
+
|
|
53
|
+
- prevent Thread[:rufus_scheduler_time] -> nil, gh-156
|
|
54
|
+
- fix inconsistency in Job#start_work_thread
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
== rufus-scheduler - 3.1.2 released 2015/05/23
|
|
58
|
+
|
|
59
|
+
- avoid cron/:first_at infinite loop, thanks https://github.com/pouellet
|
|
60
|
+
|
|
61
|
+
|
|
5
62
|
== rufus-scheduler - 3.1.1 released 2015/04/19
|
|
6
63
|
|
|
7
64
|
- fix ZoTime.is_timezone? on OSX, thanks https://github.com/yaauie
|
data/CREDITS.txt
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
== Contributors
|
|
6
6
|
|
|
7
|
+
- Balasankar C (https://github.com/balasankarc) fix CronJob spec vs December
|
|
8
|
+
- Matthieu Rosinski (https://github.com/Korrigan) prevent "every" shifts
|
|
9
|
+
- vivitar (https://github.com/vivitar) silenced a set of Ruby warnings
|
|
10
|
+
- Jon McPherson (https://github.com/JonMcPherson) :first_in => 0 back
|
|
11
|
+
- Calinoiu Alexandru Nicolae (https://github.com/alexandru-calinoiu) CronLine#prev_second fix
|
|
12
|
+
- Alyssa Pohahau (https://github.com/alyssa) out of DST transition specs
|
|
13
|
+
- Claude Vessaz (https://github.com/claudeatsafe) ack #unscheduled_at in #scheduled?
|
|
14
|
+
- 김성식 (https://github.com/kssminus) job id uniqueness effort
|
|
15
|
+
- Jesse Willet (https://github.com/jhw-at-prosperworks-com) cron vs "*/10"
|
|
16
|
+
- Pascal Ouellet (https://github.com/pouellet) Scheduler#timeline loop fix
|
|
7
17
|
- Ryan Biesemeyer (https://github.com/yaauie) ZoTime.is_timezone? on OSX
|
|
8
18
|
- Ketan Padegaonkar (https://github.com/ketan) .brute_frequency improvement
|
|
9
19
|
- Gabriel Gilder (https://github.com/ggilder) LA DST specs
|
|
@@ -36,6 +46,11 @@
|
|
|
36
46
|
|
|
37
47
|
== Feedback
|
|
38
48
|
|
|
49
|
+
- Eduardo Maia - https://github.com/emaiax - rufus and the Rails console
|
|
50
|
+
- Suisea - https://github.com/suisea - readme rewording
|
|
51
|
+
- Radek - http://stackoverflow.com/users/250422 - gh-166
|
|
52
|
+
- Patrik Ragnarsson - https://github.com/dentarg - timeout vs nil, gh-156
|
|
53
|
+
- twitter @adefilaedward1 - typo in readme
|
|
39
54
|
- Michael Guymon - https://github.com/mguymon - #next_time vs :first_at
|
|
40
55
|
- junhanamaki - https://github.com/junhanamaki - #next_time and dst ambiguities
|
|
41
56
|
- kreynolds (tossrock) - inspiration for #occurrences
|
data/README.md
CHANGED
|
@@ -75,10 +75,10 @@ There is no EventMachine-based scheduler anymore.
|
|
|
75
75
|
|
|
76
76
|
## I don't know what this Ruby thing is, where are my Rails?
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
I'll drive you right to the [tracks](#so-rails).
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
##
|
|
81
|
+
## Notable changes:
|
|
82
82
|
|
|
83
83
|
* As said, no more EventMachine-based scheduler
|
|
84
84
|
* ```scheduler.every('100') {``` will schedule every 100 seconds (previously, it would have been 0.1s). This aligns rufus-scheduler on Ruby's ```sleep(100)```
|
|
@@ -123,7 +123,8 @@ Yes, issues can be reported in [rufus-scheduler issues](https://github.com/jmett
|
|
|
123
123
|
* [I want a refund](http://blog.nodejitsu.com/getting-refunds-on-open-source-projects)
|
|
124
124
|
* [Passenger and rufus-scheduler](http://stackoverflow.com/questions/18108719/debugging-rufus-scheduler/18156180#18156180)
|
|
125
125
|
* [Passenger and rufus-scheduler (2)](http://stackoverflow.com/questions/21861387/rufus-cron-job-not-working-in-apache-passenger#answer-21868555)
|
|
126
|
-
* [
|
|
126
|
+
* [The scheduler comes up when running the Rails console](https://github.com/jmettraux/rufus-scheduler#avoid-scheduling-when-running-the-ruby-on-rails-console)
|
|
127
|
+
* [I don't get any of this, I just want it to work in my Rails application](#so-rails)
|
|
127
128
|
|
|
128
129
|
|
|
129
130
|
## scheduling
|
|
@@ -1399,6 +1400,7 @@ s = Rufus::Scheduler.singleton
|
|
|
1399
1400
|
s.every '1m' do
|
|
1400
1401
|
|
|
1401
1402
|
Rails.logger.info "hello, it's #{Time.now}"
|
|
1403
|
+
Rails.logger.flush
|
|
1402
1404
|
end
|
|
1403
1405
|
```
|
|
1404
1406
|
|
|
@@ -1427,6 +1429,49 @@ The rufus-scheduler singleton is instantiated in the ```config/initializers/sche
|
|
|
1427
1429
|
|
|
1428
1430
|
*Warning*: this works well with single-process Ruby servers like Webrick and Thin. Using rufus-scheduler with Passenger or Unicorn requires a bit more knowledge and tuning, gently provided by a bit of googling and reading, see [Faq](#faq) above.
|
|
1429
1431
|
|
|
1432
|
+
### avoid scheduling when running the Ruby on Rails console
|
|
1433
|
+
|
|
1434
|
+
(Written in reply to https://github.com/jmettraux/rufus-scheduler/issues/186 )
|
|
1435
|
+
|
|
1436
|
+
If you don't want rufus-scheduler to kick in when running the Ruby on Rails console, you can wrap your initializer in a conditional:
|
|
1437
|
+
|
|
1438
|
+
```ruby
|
|
1439
|
+
#
|
|
1440
|
+
# config/initializers/scheduler.rb
|
|
1441
|
+
|
|
1442
|
+
require 'rufus-scheduler'
|
|
1443
|
+
|
|
1444
|
+
s = Rufus::Scheduler.singleton
|
|
1445
|
+
|
|
1446
|
+
|
|
1447
|
+
unless defined?(Rails::Console)
|
|
1448
|
+
# only schedule when not running from the Rails on Rails console
|
|
1449
|
+
|
|
1450
|
+
s.every '1m' do
|
|
1451
|
+
|
|
1452
|
+
Rails.logger.info "hello, it's #{Time.now}"
|
|
1453
|
+
Rails.logger.flush
|
|
1454
|
+
end
|
|
1455
|
+
end
|
|
1456
|
+
```
|
|
1457
|
+
|
|
1458
|
+
It should work for Ruby on Rails 3 and 4.
|
|
1459
|
+
|
|
1460
|
+
### rails server -d
|
|
1461
|
+
|
|
1462
|
+
(Written in reply to https://github.com/jmettraux/rufus-scheduler/issues/165 )
|
|
1463
|
+
|
|
1464
|
+
There is the handy `rails server -d` that starts a development Rails as a daemon. The annoying thing is that the scheduler as seen above is started in the main process that then gets forked and daemonized. The rufus-scheduler thread (and any other thread) gets lost, no scheduling happens.
|
|
1465
|
+
|
|
1466
|
+
I avoid running `-d` in development mode and bother about daemonizing only for production deployment.
|
|
1467
|
+
|
|
1468
|
+
These are two well crafted articles on process daemonization, please read them:
|
|
1469
|
+
|
|
1470
|
+
* http://www.mikeperham.com/2014/09/22/dont-daemonize-your-daemons/
|
|
1471
|
+
* http://www.mikeperham.com/2014/07/07/use-runit/
|
|
1472
|
+
|
|
1473
|
+
If, anyway, you need something like `rails server -d`, why not try `bundle exec unicorn -D` instead? In my (limited) experience, it worked out of the box (well, had to add `gem 'unicorn'` to `Gemfile` first).
|
|
1474
|
+
|
|
1430
1475
|
|
|
1431
1476
|
## support
|
|
1432
1477
|
|
|
@@ -42,13 +42,13 @@ class Rufus::Scheduler
|
|
|
42
42
|
attr_reader :hours
|
|
43
43
|
attr_reader :days
|
|
44
44
|
attr_reader :months
|
|
45
|
+
#attr_reader :monthdays # reader defined below
|
|
45
46
|
attr_reader :weekdays
|
|
46
|
-
attr_reader :monthdays
|
|
47
47
|
attr_reader :timezone
|
|
48
48
|
|
|
49
49
|
def initialize(line)
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
fail ArgumentError.new(
|
|
52
52
|
"not a string: #{line.inspect}"
|
|
53
53
|
) unless line.is_a?(String)
|
|
54
54
|
|
|
@@ -58,7 +58,7 @@ class Rufus::Scheduler
|
|
|
58
58
|
|
|
59
59
|
@timezone = items.pop if ZoTime.is_timezone?(items.last)
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
fail ArgumentError.new(
|
|
62
62
|
"not a valid cronline : '#{line}'"
|
|
63
63
|
) unless items.length == 5 or items.length == 6
|
|
64
64
|
|
|
@@ -73,7 +73,7 @@ class Rufus::Scheduler
|
|
|
73
73
|
|
|
74
74
|
[ @seconds, @minutes, @hours, @months ].each do |es|
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
fail ArgumentError.new(
|
|
77
77
|
"invalid cronline: '#{line}'"
|
|
78
78
|
) if es && es.find { |e| ! e.is_a?(Fixnum) }
|
|
79
79
|
end
|
|
@@ -186,19 +186,6 @@ class Rufus::Scheduler
|
|
|
186
186
|
time
|
|
187
187
|
end
|
|
188
188
|
|
|
189
|
-
if RUBY_VERSION >= '1.9'
|
|
190
|
-
def toa(item)
|
|
191
|
-
item == nil ? nil : item.to_a
|
|
192
|
-
end
|
|
193
|
-
else
|
|
194
|
-
def toi(item); item.is_a?(String) ? item.hash.abs : item.to_i; end
|
|
195
|
-
protected :toi
|
|
196
|
-
def toa(item)
|
|
197
|
-
item.is_a?(Set) ? item.to_a.sort_by { |e| toi(e) } : item
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
protected :toa
|
|
201
|
-
|
|
202
189
|
# Returns an array of 6 arrays (seconds, minutes, hours, days,
|
|
203
190
|
# months, weekdays).
|
|
204
191
|
# This method is used by the cronline unit tests.
|
|
@@ -228,18 +215,18 @@ class Rufus::Scheduler
|
|
|
228
215
|
|
|
229
216
|
return brute_frequency unless @seconds && @seconds.length > 1
|
|
230
217
|
|
|
231
|
-
delta = 60
|
|
232
218
|
secs = toa(@seconds)
|
|
233
|
-
prev = secs[0]
|
|
234
219
|
|
|
235
|
-
secs[1..-1].
|
|
220
|
+
secs[1..-1].inject([ secs[0], 60 ]) { |(prev, delta), sec|
|
|
236
221
|
d = sec - prev
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
delta
|
|
222
|
+
[ sec, d < delta ? d : delta ]
|
|
223
|
+
}[1]
|
|
241
224
|
end
|
|
242
225
|
|
|
226
|
+
# Caching facility. Currently only used for brute frequencies.
|
|
227
|
+
#
|
|
228
|
+
@cache = {}; class << self; attr_reader :cache; end
|
|
229
|
+
|
|
243
230
|
# Returns the shortest delta between two potential occurences of the
|
|
244
231
|
# schedule described by this cronline.
|
|
245
232
|
#
|
|
@@ -256,16 +243,13 @@ class Rufus::Scheduler
|
|
|
256
243
|
# Of course, this method can get VERY slow if you call on it a second-
|
|
257
244
|
# based cronline...
|
|
258
245
|
#
|
|
259
|
-
# Since it's a rarely used method, I haven't taken the time to make it
|
|
260
|
-
# smarter/faster.
|
|
261
|
-
#
|
|
262
|
-
# One obvious improvement would be to cache the result once computed...
|
|
263
|
-
#
|
|
264
|
-
# See https://github.com/jmettraux/rufus-scheduler/issues/89
|
|
265
|
-
# for a discussion about this method.
|
|
266
|
-
#
|
|
267
246
|
def brute_frequency
|
|
268
247
|
|
|
248
|
+
key = "brute_frequency:#{@original}"
|
|
249
|
+
|
|
250
|
+
delta = self.class.cache[key]
|
|
251
|
+
return delta if delta
|
|
252
|
+
|
|
269
253
|
delta = 366 * DAY_S
|
|
270
254
|
|
|
271
255
|
t0 = previous_time(Time.local(2000, 1, 1))
|
|
@@ -285,16 +269,14 @@ class Rufus::Scheduler
|
|
|
285
269
|
t0 = t1
|
|
286
270
|
end
|
|
287
271
|
|
|
288
|
-
delta
|
|
272
|
+
self.class.cache[key] = delta
|
|
289
273
|
end
|
|
290
274
|
|
|
291
|
-
protected
|
|
292
|
-
|
|
293
275
|
def next_second(time)
|
|
294
276
|
|
|
295
|
-
secs = @seconds
|
|
277
|
+
secs = toa(@seconds)
|
|
296
278
|
|
|
297
|
-
return secs.
|
|
279
|
+
return secs.first + 60 - time.sec if time.sec > secs.last
|
|
298
280
|
|
|
299
281
|
secs.shift while secs.first < time.sec
|
|
300
282
|
|
|
@@ -303,13 +285,32 @@ class Rufus::Scheduler
|
|
|
303
285
|
|
|
304
286
|
def prev_second(time)
|
|
305
287
|
|
|
306
|
-
secs = @seconds
|
|
288
|
+
secs = toa(@seconds)
|
|
289
|
+
|
|
290
|
+
return time.sec + 60 - secs.last if time.sec < secs.first
|
|
307
291
|
|
|
308
292
|
secs.pop while time.sec < secs.last
|
|
309
293
|
|
|
310
294
|
time.sec - secs.last
|
|
311
295
|
end
|
|
312
296
|
|
|
297
|
+
protected
|
|
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
|
+
|
|
313
314
|
WEEKDAYS = %w[ sun mon tue wed thu fri sat ]
|
|
314
315
|
DAY_S = 24 * 3600
|
|
315
316
|
WEEK_S = 7 * DAY_S
|
|
@@ -327,7 +328,7 @@ class Rufus::Scheduler
|
|
|
327
328
|
|
|
328
329
|
if m = it.match(/^(.+)#(l|-?[12345])$/)
|
|
329
330
|
|
|
330
|
-
|
|
331
|
+
fail ArgumentError.new(
|
|
331
332
|
"ranges are not supported for monthdays (#{it})"
|
|
332
333
|
) if m[1].index('-')
|
|
333
334
|
|
|
@@ -340,7 +341,7 @@ class Rufus::Scheduler
|
|
|
340
341
|
expr = it.dup
|
|
341
342
|
WEEKDAYS.each_with_index { |a, i| expr.gsub!(/#{a}/, i.to_s) }
|
|
342
343
|
|
|
343
|
-
|
|
344
|
+
fail ArgumentError.new(
|
|
344
345
|
"invalid weekday expression (#{it})"
|
|
345
346
|
) if expr !~ /^0*[0-7](-0*[0-7])?$/
|
|
346
347
|
|
|
@@ -351,7 +352,7 @@ class Rufus::Scheduler
|
|
|
351
352
|
end
|
|
352
353
|
end
|
|
353
354
|
|
|
354
|
-
weekdays = weekdays.uniq if weekdays
|
|
355
|
+
weekdays = weekdays.uniq.sort if weekdays
|
|
355
356
|
|
|
356
357
|
[ weekdays, monthdays ]
|
|
357
358
|
end
|
|
@@ -362,10 +363,12 @@ class Rufus::Scheduler
|
|
|
362
363
|
|
|
363
364
|
r = item.split(',').map { |i| parse_range(i.strip, min, max) }.flatten
|
|
364
365
|
|
|
365
|
-
|
|
366
|
+
fail ArgumentError.new(
|
|
366
367
|
"found duplicates in #{item.inspect}"
|
|
367
368
|
) if r.uniq.size < r.size
|
|
368
369
|
|
|
370
|
+
r = sc_sort(r)
|
|
371
|
+
|
|
369
372
|
Set.new(r)
|
|
370
373
|
end
|
|
371
374
|
|
|
@@ -375,11 +378,11 @@ class Rufus::Scheduler
|
|
|
375
378
|
|
|
376
379
|
return %w[ L ] if item == 'L'
|
|
377
380
|
|
|
378
|
-
item = '*' + item if item
|
|
381
|
+
item = '*' + item if item[0, 1] == '/'
|
|
379
382
|
|
|
380
383
|
m = item.match(RANGE_REGEX)
|
|
381
384
|
|
|
382
|
-
|
|
385
|
+
fail ArgumentError.new(
|
|
383
386
|
"cannot parse #{item.inspect}"
|
|
384
387
|
) unless m
|
|
385
388
|
|
|
@@ -393,7 +396,7 @@ class Rufus::Scheduler
|
|
|
393
396
|
inc = m[3]
|
|
394
397
|
inc = inc ? inc.to_i : 1
|
|
395
398
|
|
|
396
|
-
|
|
399
|
+
fail ArgumentError.new(
|
|
397
400
|
"#{item.inspect} is not in range #{min}..#{max}"
|
|
398
401
|
) if sta < min || edn > max
|
|
399
402
|
|
data/lib/rufus/scheduler/jobs.rb
CHANGED
|
@@ -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]
|
|
@@ -235,7 +235,7 @@ module Rufus
|
|
|
235
235
|
|
|
236
236
|
rescue StandardError => se
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
fail se unless do_rescue
|
|
239
239
|
|
|
240
240
|
return if se.is_a?(KillSignal) # discard
|
|
241
241
|
|
|
@@ -284,7 +284,7 @@ module Rufus
|
|
|
284
284
|
Thread.new do
|
|
285
285
|
|
|
286
286
|
Thread.current[@scheduler.thread_key] = true
|
|
287
|
-
Thread.current[:
|
|
287
|
+
Thread.current[:rufus_scheduler_work_thread] = true
|
|
288
288
|
|
|
289
289
|
loop do
|
|
290
290
|
|
|
@@ -351,7 +351,7 @@ module Rufus
|
|
|
351
351
|
self.class.name.split(':').last.downcase[0..-4],
|
|
352
352
|
@scheduled_at.to_f,
|
|
353
353
|
@next_time.to_f,
|
|
354
|
-
|
|
354
|
+
self.hash.abs
|
|
355
355
|
].map(&:to_s).join('_')
|
|
356
356
|
end
|
|
357
357
|
|
|
@@ -391,7 +391,7 @@ module Rufus
|
|
|
391
391
|
attr_reader :paused_at
|
|
392
392
|
|
|
393
393
|
attr_reader :first_at
|
|
394
|
-
|
|
394
|
+
attr_reader :last_at
|
|
395
395
|
attr_accessor :times
|
|
396
396
|
|
|
397
397
|
def initialize(scheduler, duration, opts, block)
|
|
@@ -402,7 +402,7 @@ module Rufus
|
|
|
402
402
|
|
|
403
403
|
@times = opts[:times]
|
|
404
404
|
|
|
405
|
-
|
|
405
|
+
fail ArgumentError.new(
|
|
406
406
|
"cannot accept :times => #{@times.inspect}, not nil or an int"
|
|
407
407
|
) unless @times == nil || @times.is_a?(Fixnum)
|
|
408
408
|
|
|
@@ -416,27 +416,34 @@ module Rufus
|
|
|
416
416
|
|
|
417
417
|
def first_at=(first)
|
|
418
418
|
|
|
419
|
-
return @first_at = nil if first == nil
|
|
419
|
+
return (@first_at = nil) if first == nil
|
|
420
420
|
|
|
421
|
-
|
|
422
|
-
|
|
421
|
+
n0 = Time.now
|
|
422
|
+
n1 = n0 + 0.003
|
|
423
|
+
|
|
424
|
+
first = n0 if first == :now || first == :immediately || first == 0
|
|
423
425
|
|
|
424
426
|
@first_at = Rufus::Scheduler.parse_to_time(first)
|
|
427
|
+
@first_at = n1 if @first_at >= n0 && @first_at < n1
|
|
425
428
|
|
|
426
|
-
|
|
429
|
+
fail ArgumentError.new(
|
|
427
430
|
"cannot set first[_at|_in] in the past: " +
|
|
428
431
|
"#{first.inspect} -> #{@first_at.inspect}"
|
|
429
|
-
) if
|
|
432
|
+
) if @first_at < n0
|
|
433
|
+
|
|
434
|
+
@first_at
|
|
430
435
|
end
|
|
431
436
|
|
|
432
437
|
def last_at=(last)
|
|
433
438
|
|
|
434
439
|
@last_at = last ? Rufus::Scheduler.parse_to_time(last) : nil
|
|
435
440
|
|
|
436
|
-
|
|
441
|
+
fail ArgumentError.new(
|
|
437
442
|
"cannot set last[_at|_in] in the past: " +
|
|
438
443
|
"#{last.inspect} -> #{@last_at.inspect}"
|
|
439
444
|
) if last && @last_at < Time.now
|
|
445
|
+
|
|
446
|
+
@last_at
|
|
440
447
|
end
|
|
441
448
|
|
|
442
449
|
def trigger(time)
|
|
@@ -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,7 +529,7 @@ 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
|
|
@@ -536,9 +543,12 @@ module Rufus
|
|
|
536
543
|
|
|
537
544
|
return if is_post
|
|
538
545
|
|
|
546
|
+
n = Time.now
|
|
547
|
+
|
|
539
548
|
@next_time =
|
|
540
|
-
if @first_at == nil || @first_at <
|
|
541
|
-
(trigger_time ||
|
|
549
|
+
if @first_at == nil || @first_at < n
|
|
550
|
+
nt = (@next_time || trigger_time || n) + @frequency
|
|
551
|
+
nt > n ? nt : (trigger_time || n) + @frequency
|
|
542
552
|
else
|
|
543
553
|
@first_at
|
|
544
554
|
end
|
|
@@ -560,7 +570,7 @@ module Rufus
|
|
|
560
570
|
|
|
561
571
|
@interval = Rufus::Scheduler.parse_in(@original)
|
|
562
572
|
|
|
563
|
-
|
|
573
|
+
fail ArgumentError.new(
|
|
564
574
|
"cannot schedule #{self.class} with an interval " +
|
|
565
575
|
"of #{@interval.inspect} (#{@original.inspect})"
|
|
566
576
|
) if @interval <= 0
|
|
@@ -621,7 +631,7 @@ module Rufus
|
|
|
621
631
|
|
|
622
632
|
def next_time_from(time)
|
|
623
633
|
|
|
624
|
-
if @first_at == nil || @first_at
|
|
634
|
+
if @first_at == nil || @first_at <= time
|
|
625
635
|
@cron_line.next_time(time)
|
|
626
636
|
else
|
|
627
637
|
@first_at
|
data/lib/rufus/scheduler/util.rb
CHANGED
|
@@ -38,7 +38,7 @@ module Rufus
|
|
|
38
38
|
parse_cron(o, opts) ||
|
|
39
39
|
parse_in(o, opts) || # covers 'every' schedule strings
|
|
40
40
|
parse_at(o, opts) ||
|
|
41
|
-
|
|
41
|
+
fail(ArgumentError.new("couldn't parse \"#{o}\""))
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def self.parse_in(o, opts={})
|
|
@@ -53,7 +53,7 @@ module Rufus
|
|
|
53
53
|
rescue StandardError => se
|
|
54
54
|
|
|
55
55
|
return nil if opts[:no_error]
|
|
56
|
-
|
|
56
|
+
fail se
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def self.parse_cron(o, opts)
|
|
@@ -63,7 +63,7 @@ module Rufus
|
|
|
63
63
|
rescue ArgumentError => ae
|
|
64
64
|
|
|
65
65
|
return nil if opts[:no_error]
|
|
66
|
-
|
|
66
|
+
fail ae
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def self.parse_to_time(o)
|
|
@@ -72,7 +72,7 @@ module Rufus
|
|
|
72
72
|
t = parse(t) if t.is_a?(String)
|
|
73
73
|
t = Time.now + t if t.is_a?(Numeric)
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
fail ArgumentError.new(
|
|
76
76
|
"cannot turn #{o.inspect} to a point in time, doesn't make sense"
|
|
77
77
|
) unless t.is_a?(Time)
|
|
78
78
|
|
|
@@ -132,7 +132,7 @@ module Rufus
|
|
|
132
132
|
m = string.match(/^(-?)([\d\.#{DURATION_LETTERS}]+)$/)
|
|
133
133
|
|
|
134
134
|
return nil if m.nil? && opts[:no_error]
|
|
135
|
-
|
|
135
|
+
fail ArgumentError.new("cannot parse '#{string}'") if m.nil?
|
|
136
136
|
|
|
137
137
|
mod = m[1] == '-' ? -1.0 : 1.0
|
|
138
138
|
val = 0.0
|
|
@@ -150,9 +150,7 @@ module Rufus
|
|
|
150
150
|
elsif opts[:no_error]
|
|
151
151
|
return nil
|
|
152
152
|
else
|
|
153
|
-
|
|
154
|
-
"cannot parse '#{string}' (especially '#{s}')"
|
|
155
|
-
)
|
|
153
|
+
fail ArgumentError.new("cannot parse '#{string}' (especially '#{s}')")
|
|
156
154
|
end
|
|
157
155
|
break unless m && m[3]
|
|
158
156
|
s = m[3]
|
|
@@ -151,6 +151,7 @@ America/Argentina/Catamarca America/Indiana/Indianapolis
|
|
|
151
151
|
America/North_Dakota/New_Salem America/Argentina/Rio_Gallegos
|
|
152
152
|
America/Argentina/Buenos_Aires America/Argentina/ComodRivadavia
|
|
153
153
|
]
|
|
154
|
+
TIMEZONEs = TIMEZONES.collect(&:downcase)
|
|
154
155
|
|
|
155
156
|
##
|
|
156
157
|
## http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
|
|
@@ -47,13 +47,19 @@ class Rufus::Scheduler
|
|
|
47
47
|
|
|
48
48
|
t = Time.at(@seconds)
|
|
49
49
|
|
|
50
|
-
if t.isdst
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
else
|
|
55
|
-
|
|
56
|
-
end
|
|
50
|
+
#if t.isdst
|
|
51
|
+
# t1 = Time.at(@seconds + 3600)
|
|
52
|
+
# t = t1 if t.zone != t1.zone && t.hour == t1.hour && t.min == t1.min
|
|
53
|
+
# # ambiguous TZ (getting out of DST)
|
|
54
|
+
#else
|
|
55
|
+
# t.hour # force t to compute itself
|
|
56
|
+
#end
|
|
57
|
+
#
|
|
58
|
+
# jump out of DST as soon as possible, jumps 1h as seen from UTC
|
|
59
|
+
|
|
60
|
+
t.hour # force t to compute itself
|
|
61
|
+
#
|
|
62
|
+
# stay in DST as long as possible, no jump seen from UTC
|
|
57
63
|
|
|
58
64
|
t
|
|
59
65
|
end
|
|
@@ -95,7 +101,7 @@ class Rufus::Scheduler
|
|
|
95
101
|
begin
|
|
96
102
|
DateTime.parse(str)
|
|
97
103
|
rescue
|
|
98
|
-
|
|
104
|
+
fail ArgumentError, "no time information in #{o.inspect}"
|
|
99
105
|
end if RUBY_VERSION < '1.9.0'
|
|
100
106
|
|
|
101
107
|
zone = nil
|
|
@@ -121,17 +127,23 @@ class Rufus::Scheduler
|
|
|
121
127
|
def self.is_timezone?(str)
|
|
122
128
|
|
|
123
129
|
return false if str == nil
|
|
130
|
+
return false if str == '*'
|
|
131
|
+
|
|
132
|
+
return false if str.index('#')
|
|
133
|
+
# "sun#2", etc... On OSX would go all the way to true
|
|
124
134
|
|
|
125
135
|
return true if Time.zone_offset(str)
|
|
126
|
-
return true if str == 'Zulu' || str == 'UTC'
|
|
127
136
|
|
|
128
137
|
return !! (::TZInfo::Timezone.get(str) rescue nil) if defined?(::TZInfo)
|
|
129
138
|
|
|
139
|
+
return true if TIMEZONES.include?(str)
|
|
140
|
+
return true if TIMEZONEs.include?(str)
|
|
141
|
+
|
|
130
142
|
t = ZoTime.new(0, str).time
|
|
131
143
|
|
|
132
144
|
return false if t.zone == ''
|
|
133
145
|
return false if t.zone == 'UTC'
|
|
134
|
-
return false if
|
|
146
|
+
return false if t.utc_offset == 0 && str.start_with?(t.zone)
|
|
135
147
|
# 3 common fallbacks...
|
|
136
148
|
|
|
137
149
|
return false if RUBY_PLATFORM.include?('java') && ! envtzable?(str)
|