rufus-scheduler 3.1.0 → 3.1.9
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.
- checksums.yaml +7 -0
- data/CHANGELOG.txt +48 -0
- data/CREDITS.txt +11 -0
- data/README.md +18 -2
- data/lib/rufus/scheduler/cronline.rb +28 -26
- data/lib/rufus/scheduler/jobs.rb +4 -4
- data/lib/rufus/scheduler/zones.rb +1 -0
- data/lib/rufus/scheduler/zotime.rb +24 -11
- data/lib/rufus/scheduler.rb +4 -4
- data/spec/cronline_spec.rb +422 -39
- data/spec/job_spec.rb +40 -0
- data/spec/scheduler_spec.rb +16 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/zotime_spec.rb +8 -13
- data/t.txt +31 -0
- metadata +44 -53
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 03122e92f3b47a4af3d12b06762f5f4caa604341
|
|
4
|
+
data.tar.gz: 8db6b1570347d1ffa1871fe9d90163729fbf7516
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0bf2d0ab22e975dc6832fc651dd415708a998960b4b9503865fe560c9b78284b54ac2b5957d8c912d1415776898e211eb6fe6a56c456613df85f5b4afcf35e0f
|
|
7
|
+
data.tar.gz: 52b001210ccea2c628e4a95e2bde023725cbb1ce9ee78bd635cfedddafcbed9851abda8eb0edb46e5816ba7ddc80e55dae256588a6caf079f9ebd126d5dbd3c7
|
data/CHANGELOG.txt
CHANGED
|
@@ -2,6 +2,54 @@
|
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
== rufus-scheduler - 3.1.9 released 2015-11-12
|
|
6
|
+
|
|
7
|
+
- fix potential RuntimeError in CronLine#prev_second,
|
|
8
|
+
by Alexandru https://github.com/alexandru-calinoiu
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
== rufus-scheduler - 3.1.8 released 2015-11-10
|
|
12
|
+
|
|
13
|
+
- stop jumping eagerly out of DST, fix for one hour jump when leaving DST
|
|
14
|
+
thanks Alyssa http://github.com/alyssa
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
== rufus-scheduler - 3.1.7 released 2015-10-15
|
|
18
|
+
|
|
19
|
+
- ack #unscheduled_at in #scheduled?, by Claude https://github.com/claudeatsafe
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
== rufus-scheduler - 3.1.6 released 2015-10-01
|
|
23
|
+
|
|
24
|
+
- fix job id uniqueness (JRuby), thanks 김성식 https://github.com/kssminus
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
== rufus-scheduler - 3.1.5 released 2015-09-25
|
|
28
|
+
|
|
29
|
+
- fix for "not a valid cronline" on "mingw" Ruby distributions, gh-166
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
== rufus-scheduler - 3.1.4 released 2015/08/29
|
|
33
|
+
|
|
34
|
+
- fix cron issue reported by Jesse https://github.com/jhw-at-prosperworks-com
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
== rufus-scheduler - 3.1.3 released 2015/06/20
|
|
38
|
+
|
|
39
|
+
- prevent Thread[:rufus_scheduler_time] -> nil, gh-156
|
|
40
|
+
- fix inconsistency in Job#start_work_thread
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
== rufus-scheduler - 3.1.2 released 2015/05/23
|
|
44
|
+
|
|
45
|
+
- avoid cron/:first_at infinite loop, thanks https://github.com/pouellet
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
== rufus-scheduler - 3.1.1 released 2015/04/19
|
|
49
|
+
|
|
50
|
+
- fix ZoTime.is_timezone? on OSX, thanks https://github.com/yaauie
|
|
51
|
+
|
|
52
|
+
|
|
5
53
|
== rufus-scheduler - 3.1.0 released 2015/04/18
|
|
6
54
|
|
|
7
55
|
- go without tzinfo (and its dependencies)
|
data/CREDITS.txt
CHANGED
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
== Contributors
|
|
6
6
|
|
|
7
|
+
- Calinoiu Alexandru Nicolae (https://github.com/alexandru-calinoiu) CronLine#prev_second fix
|
|
8
|
+
- Alyssa Pohahau (https://github.com/alyssa) out of DST transition specs
|
|
9
|
+
- Claude Vessaz (https://github.com/claudeatsafe) ack #unscheduled_at in #scheduled?
|
|
10
|
+
- 김성식 (https://github.com/kssminus) job id uniqueness effort
|
|
11
|
+
- Jesse Willet (https://github.com/jhw-at-prosperworks-com) cron vs "*/10"
|
|
12
|
+
- Pascal Ouellet (https://github.com/pouellet) Scheduler#timeline loop fix
|
|
13
|
+
- Ryan Biesemeyer (https://github.com/yaauie) ZoTime.is_timezone? on OSX
|
|
7
14
|
- Ketan Padegaonkar (https://github.com/ketan) .brute_frequency improvement
|
|
8
15
|
- Gabriel Gilder (https://github.com/ggilder) LA DST specs
|
|
9
16
|
- Sterling Paramore (https://github.com/gnilrets) underscore TZ fix
|
|
@@ -35,6 +42,10 @@
|
|
|
35
42
|
|
|
36
43
|
== Feedback
|
|
37
44
|
|
|
45
|
+
- Suisea - https://github.com/suisea - readme rewording
|
|
46
|
+
- Radek - http://stackoverflow.com/users/250422 - gh-166
|
|
47
|
+
- Patrik Ragnarsson - https://github.com/dentarg - timeout vs nil, gh-156
|
|
48
|
+
- twitter @adefilaedward1 - typo in readme
|
|
38
49
|
- Michael Guymon - https://github.com/mguymon - #next_time vs :first_at
|
|
39
50
|
- junhanamaki - https://github.com/junhanamaki - #next_time and dst ambiguities
|
|
40
51
|
- 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)```
|
|
@@ -1399,6 +1399,7 @@ s = Rufus::Scheduler.singleton
|
|
|
1399
1399
|
s.every '1m' do
|
|
1400
1400
|
|
|
1401
1401
|
Rails.logger.info "hello, it's #{Time.now}"
|
|
1402
|
+
Rails.logger.flush
|
|
1402
1403
|
end
|
|
1403
1404
|
```
|
|
1404
1405
|
|
|
@@ -1427,6 +1428,21 @@ The rufus-scheduler singleton is instantiated in the ```config/initializers/sche
|
|
|
1427
1428
|
|
|
1428
1429
|
*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
1430
|
|
|
1431
|
+
### rails server -d
|
|
1432
|
+
|
|
1433
|
+
(Written in reply to https://github.com/jmettraux/rufus-scheduler/issues/165 )
|
|
1434
|
+
|
|
1435
|
+
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.
|
|
1436
|
+
|
|
1437
|
+
I avoid running `-d` in development mode and bother about daemonizing only for production deployment.
|
|
1438
|
+
|
|
1439
|
+
These are two well crafted articles on process daemonization, please read them:
|
|
1440
|
+
|
|
1441
|
+
* http://www.mikeperham.com/2014/09/22/dont-daemonize-your-daemons/
|
|
1442
|
+
* http://www.mikeperham.com/2014/07/07/use-runit/
|
|
1443
|
+
|
|
1444
|
+
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).
|
|
1445
|
+
|
|
1430
1446
|
|
|
1431
1447
|
## support
|
|
1432
1448
|
|
|
@@ -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,16 +215,12 @@ 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
|
|
|
243
226
|
# Returns the shortest delta between two potential occurences of the
|
|
@@ -288,13 +271,11 @@ class Rufus::Scheduler
|
|
|
288
271
|
delta
|
|
289
272
|
end
|
|
290
273
|
|
|
291
|
-
protected
|
|
292
|
-
|
|
293
274
|
def next_second(time)
|
|
294
275
|
|
|
295
|
-
secs = @seconds
|
|
276
|
+
secs = toa(@seconds)
|
|
296
277
|
|
|
297
|
-
return secs.
|
|
278
|
+
return secs.first + 60 - time.sec if time.sec > secs.last
|
|
298
279
|
|
|
299
280
|
secs.shift while secs.first < time.sec
|
|
300
281
|
|
|
@@ -303,13 +284,32 @@ class Rufus::Scheduler
|
|
|
303
284
|
|
|
304
285
|
def prev_second(time)
|
|
305
286
|
|
|
306
|
-
secs = @seconds
|
|
287
|
+
secs = toa(@seconds)
|
|
288
|
+
|
|
289
|
+
return time.sec + 60 - secs.last if time.sec < secs.first
|
|
307
290
|
|
|
308
291
|
secs.pop while time.sec < secs.last
|
|
309
292
|
|
|
310
293
|
time.sec - secs.last
|
|
311
294
|
end
|
|
312
295
|
|
|
296
|
+
protected
|
|
297
|
+
|
|
298
|
+
def sc_sort(a)
|
|
299
|
+
|
|
300
|
+
a.sort_by { |e| e.is_a?(String) ? 61 : e.to_i }
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
if RUBY_VERSION >= '1.9'
|
|
304
|
+
def toa(item)
|
|
305
|
+
item == nil ? nil : item.to_a
|
|
306
|
+
end
|
|
307
|
+
else
|
|
308
|
+
def toa(item)
|
|
309
|
+
item.is_a?(Set) ? sc_sort(item.to_a) : item
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
313
|
WEEKDAYS = %w[ sun mon tue wed thu fri sat ]
|
|
314
314
|
DAY_S = 24 * 3600
|
|
315
315
|
WEEK_S = 7 * DAY_S
|
|
@@ -351,7 +351,7 @@ class Rufus::Scheduler
|
|
|
351
351
|
end
|
|
352
352
|
end
|
|
353
353
|
|
|
354
|
-
weekdays = weekdays.uniq if weekdays
|
|
354
|
+
weekdays = weekdays.uniq.sort if weekdays
|
|
355
355
|
|
|
356
356
|
[ weekdays, monthdays ]
|
|
357
357
|
end
|
|
@@ -366,6 +366,8 @@ class Rufus::Scheduler
|
|
|
366
366
|
"found duplicates in #{item.inspect}"
|
|
367
367
|
) if r.uniq.size < r.size
|
|
368
368
|
|
|
369
|
+
r = sc_sort(r)
|
|
370
|
+
|
|
369
371
|
Set.new(r)
|
|
370
372
|
end
|
|
371
373
|
|
data/lib/rufus/scheduler/jobs.rb
CHANGED
|
@@ -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
|
|
|
@@ -473,7 +473,7 @@ module Rufus
|
|
|
473
473
|
[
|
|
474
474
|
self.class.name.split(':').last.downcase[0..-4],
|
|
475
475
|
@scheduled_at.to_f,
|
|
476
|
-
|
|
476
|
+
self.hash.abs
|
|
477
477
|
].map(&:to_s).join('_')
|
|
478
478
|
end
|
|
479
479
|
|
|
@@ -621,7 +621,7 @@ module Rufus
|
|
|
621
621
|
|
|
622
622
|
def next_time_from(time)
|
|
623
623
|
|
|
624
|
-
if @first_at == nil || @first_at
|
|
624
|
+
if @first_at == nil || @first_at <= time
|
|
625
625
|
@cron_line.next_time(time)
|
|
626
626
|
else
|
|
627
627
|
@first_at
|
|
@@ -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
|
|
@@ -121,17 +127,24 @@ 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'
|
|
127
136
|
|
|
128
137
|
return !! (::TZInfo::Timezone.get(str) rescue nil) if defined?(::TZInfo)
|
|
129
138
|
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
return true if TIMEZONES.include?(str)
|
|
140
|
+
return true if TIMEZONEs.include?(str)
|
|
141
|
+
|
|
142
|
+
t = ZoTime.new(0, str).time
|
|
132
143
|
|
|
133
144
|
return false if t.zone == ''
|
|
134
|
-
return false if
|
|
145
|
+
return false if t.zone == 'UTC'
|
|
146
|
+
return false if t.utc_offset == 0 && str.start_with?(t.zone)
|
|
147
|
+
# 3 common fallbacks...
|
|
135
148
|
|
|
136
149
|
return false if RUBY_PLATFORM.include?('java') && ! envtzable?(str)
|
|
137
150
|
|
data/lib/rufus/scheduler.rb
CHANGED
|
@@ -39,7 +39,7 @@ module Rufus
|
|
|
39
39
|
require 'rufus/scheduler/job_array'
|
|
40
40
|
require 'rufus/scheduler/locks'
|
|
41
41
|
|
|
42
|
-
VERSION = '3.1.
|
|
42
|
+
VERSION = '3.1.9'
|
|
43
43
|
|
|
44
44
|
#
|
|
45
45
|
# A common error class for rufus-scheduler
|
|
@@ -387,7 +387,7 @@ module Rufus
|
|
|
387
387
|
|
|
388
388
|
job, job_id = fetch(job_or_job_id)
|
|
389
389
|
|
|
390
|
-
!! (job && job.next_time != nil)
|
|
390
|
+
!! (job && job.unscheduled_at.nil? && job.next_time != nil)
|
|
391
391
|
end
|
|
392
392
|
|
|
393
393
|
# Lists all the threads associated with this scheduler.
|
|
@@ -592,11 +592,11 @@ module Rufus
|
|
|
592
592
|
|
|
593
593
|
job = t[:rufus_scheduler_job]
|
|
594
594
|
to = t[:rufus_scheduler_timeout]
|
|
595
|
+
ts = t[:rufus_scheduler_time]
|
|
595
596
|
|
|
596
|
-
next unless job && to
|
|
597
|
+
next unless job && to && ts
|
|
597
598
|
# thread might just have become inactive (job -> nil)
|
|
598
599
|
|
|
599
|
-
ts = t[:rufus_scheduler_time]
|
|
600
600
|
to = to.is_a?(Time) ? to : ts + to
|
|
601
601
|
|
|
602
602
|
next if to > Time.now
|
data/spec/cronline_spec.rb
CHANGED
|
@@ -7,6 +7,17 @@
|
|
|
7
7
|
|
|
8
8
|
require 'spec_helper'
|
|
9
9
|
|
|
10
|
+
class Time
|
|
11
|
+
|
|
12
|
+
def to_compact_s
|
|
13
|
+
|
|
14
|
+
off = self.utc_offset / 3600
|
|
15
|
+
off = off >= 0 ? "+#{off}" : off.to_s
|
|
16
|
+
|
|
17
|
+
self.strftime('%H%M') + off + self.dup.utc.strftime('(%H%M)')
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
10
21
|
|
|
11
22
|
describe Rufus::Scheduler::CronLine do
|
|
12
23
|
|
|
@@ -32,6 +43,13 @@ describe Rufus::Scheduler::CronLine do
|
|
|
32
43
|
in_zone(tz) { tu.getlocal }
|
|
33
44
|
end
|
|
34
45
|
|
|
46
|
+
def ns(cronline, now)
|
|
47
|
+
Rufus::Scheduler::CronLine.new(cronline).next_second(now)
|
|
48
|
+
end
|
|
49
|
+
def ps(cronline, now)
|
|
50
|
+
Rufus::Scheduler::CronLine.new(cronline).prev_second(now)
|
|
51
|
+
end
|
|
52
|
+
|
|
35
53
|
def match(line, time)
|
|
36
54
|
expect(cl(line).matches?(time)).to eq(true)
|
|
37
55
|
end
|
|
@@ -66,30 +84,42 @@ describe Rufus::Scheduler::CronLine do
|
|
|
66
84
|
|
|
67
85
|
to_a '0 0 1 1 *', [ [0], [0], [0], [1], [1], nil, nil, nil ]
|
|
68
86
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
to_a '52 0 * * *', [ [0], [52], [0], nil, nil, nil, nil, nil ]
|
|
88
|
+
|
|
89
|
+
#if ruby18?
|
|
90
|
+
# to_a '0 23-24 * * *', [ [0], [0], [0, 23], nil, nil, nil, nil, nil ]
|
|
91
|
+
#else
|
|
92
|
+
# to_a '0 23-24 * * *', [ [0], [0], [23, 0], nil, nil, nil, nil, nil ]
|
|
93
|
+
#end
|
|
74
94
|
#
|
|
75
95
|
# as reported by Aimee Rose in
|
|
76
96
|
# https://github.com/jmettraux/rufus-scheduler/issues/56
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
to_a '0 23-24 * * *', [ [0], [0], [0, 23], nil, nil, nil, nil, nil ]
|
|
98
|
+
|
|
99
|
+
#if ruby18?
|
|
100
|
+
# to_a '0 23-2 * * *', [ [0], [0], [0, 1, 2, 23], nil, nil, nil, nil, nil ]
|
|
101
|
+
#else
|
|
102
|
+
# to_a '0 23-2 * * *', [ [0], [0], [23, 0, 1, 2], nil, nil, nil, nil, nil ]
|
|
103
|
+
#end
|
|
104
|
+
to_a '0 23-2 * * *', [ [0], [0], [0, 1, 2, 23], nil, nil, nil, nil, nil ]
|
|
105
|
+
|
|
106
|
+
# modulo forms work for five-field forms
|
|
107
|
+
to_a '*/17 * * * *', [[0], [0, 17, 34, 51], nil, nil, nil, nil, nil, nil]
|
|
108
|
+
to_a '13 */17 * * *', [[0], [13], [0, 17], nil, nil, nil, nil, nil]
|
|
109
|
+
|
|
110
|
+
# modulo forms work for six-field forms
|
|
111
|
+
to_a '*/17 * * * * *', [[0, 17, 34, 51], nil, nil, nil, nil, nil, nil, nil]
|
|
112
|
+
to_a '13 */17 * * * *', [[13], [0, 17, 34, 51], nil, nil, nil, nil, nil, nil]
|
|
83
113
|
end
|
|
84
114
|
|
|
85
115
|
it 'rejects invalid weekday expressions' do
|
|
86
116
|
|
|
87
|
-
expect { cl '0 17 * * MON_FRI' }.to raise_error
|
|
117
|
+
expect { cl '0 17 * * MON_FRI' }.to raise_error(ArgumentError)
|
|
88
118
|
# underline instead of dash
|
|
89
119
|
|
|
90
|
-
expect { cl '* * * * 9' }.to raise_error
|
|
91
|
-
expect { cl '* * * * 0-12' }.to raise_error
|
|
92
|
-
expect { cl '* * * * BLABLA' }.to raise_error
|
|
120
|
+
expect { cl '* * * * 9' }.to raise_error(ArgumentError)
|
|
121
|
+
expect { cl '* * * * 0-12' }.to raise_error(ArgumentError)
|
|
122
|
+
expect { cl '* * * * BLABLA' }.to raise_error(ArgumentError)
|
|
93
123
|
end
|
|
94
124
|
|
|
95
125
|
it 'rejects invalid cronlines' do
|
|
@@ -109,8 +139,8 @@ describe Rufus::Scheduler::CronLine do
|
|
|
109
139
|
'* * * * * * America/New_York',
|
|
110
140
|
[ nil, nil, nil, nil, nil, nil, nil, 'America/New_York' ])
|
|
111
141
|
|
|
112
|
-
expect { cl '* * * * * NotATimeZone' }.to raise_error
|
|
113
|
-
expect { cl '* * * * * * NotATimeZone' }.to raise_error
|
|
142
|
+
expect { cl '* * * * * NotATimeZone' }.to raise_error(ArgumentError)
|
|
143
|
+
expect { cl '* * * * * * NotATimeZone' }.to raise_error(ArgumentError)
|
|
114
144
|
end
|
|
115
145
|
|
|
116
146
|
it 'interprets cron strings with / (slashes) correctly' do
|
|
@@ -213,6 +243,36 @@ describe Rufus::Scheduler::CronLine do
|
|
|
213
243
|
# as reported by Aimee Rose in
|
|
214
244
|
# https://github.com/jmettraux/rufus-scheduler/pull/58
|
|
215
245
|
end
|
|
246
|
+
|
|
247
|
+
it 'sorts seconds' do
|
|
248
|
+
|
|
249
|
+
to_a(
|
|
250
|
+
'23,30,10 * * * * *', [ [10,23,30], nil, nil, nil, nil, nil, nil, nil ])
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it 'sorts minutes' do
|
|
254
|
+
|
|
255
|
+
to_a(
|
|
256
|
+
'23,30,10 * * * * ', [ [0], [10,23,30], nil, nil, nil, nil, nil, nil ])
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
it 'sorts days' do
|
|
260
|
+
|
|
261
|
+
to_a(
|
|
262
|
+
'* * 14,7 * * ', [ [0], nil, nil, [7, 14], nil, nil, nil, nil ])
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
it 'sorts months' do
|
|
266
|
+
|
|
267
|
+
to_a(
|
|
268
|
+
'* * * 11,3,4 * ', [ [0], nil, nil, nil, [3,4,11], nil, nil, nil ])
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it 'sorts days of week' do
|
|
272
|
+
|
|
273
|
+
to_a(
|
|
274
|
+
'* * * * Sun,Fri,2 ', [ [0], nil, nil, nil, nil, [0, 2, 5], nil, nil ])
|
|
275
|
+
end
|
|
216
276
|
end
|
|
217
277
|
|
|
218
278
|
describe '#next_time' do
|
|
@@ -346,7 +406,10 @@ describe Rufus::Scheduler::CronLine do
|
|
|
346
406
|
'30 1 31 10 * America/New_York',
|
|
347
407
|
ltz('America/New_York', 2004, 10, 1)
|
|
348
408
|
)
|
|
349
|
-
).to eq(
|
|
409
|
+
).to eq(
|
|
410
|
+
ltz('America/New_York', 0, 30, 1, 31, 10, 2004, nil, nil, true, nil)
|
|
411
|
+
# EDT summer time UTC-4
|
|
412
|
+
)
|
|
350
413
|
end
|
|
351
414
|
end
|
|
352
415
|
|
|
@@ -361,6 +424,75 @@ describe Rufus::Scheduler::CronLine do
|
|
|
361
424
|
)
|
|
362
425
|
).to eq(ltz('America/New_York', 2015, 3, 9, 2, 0, 0))
|
|
363
426
|
end
|
|
427
|
+
|
|
428
|
+
it 'understands six-field crontabs' do
|
|
429
|
+
|
|
430
|
+
expect(nt('* * * * * *',local(1970,1,1,1,1,1))).to(
|
|
431
|
+
eq(local(1970,1,1,1,1,2))
|
|
432
|
+
)
|
|
433
|
+
expect(nt('* * * * * *',local(1970,1,1,1,1,2))).to(
|
|
434
|
+
eq(local(1970,1,1,1,1,3))
|
|
435
|
+
)
|
|
436
|
+
expect(nt('*/10 * * * * *',local(1970,1,1,1,1,0))).to(
|
|
437
|
+
eq(local(1970,1,1,1,1,10))
|
|
438
|
+
)
|
|
439
|
+
expect(nt('*/10 * * * * *',local(1970,1,1,1,1,9))).to(
|
|
440
|
+
eq(local(1970,1,1,1,1,10))
|
|
441
|
+
)
|
|
442
|
+
expect(nt('*/10 * * * * *',local(1970,1,1,1,1,10))).to(
|
|
443
|
+
eq(local(1970,1,1,1,1,20))
|
|
444
|
+
)
|
|
445
|
+
expect(nt('*/10 * * * * *',local(1970,1,1,1,1,40))).to(
|
|
446
|
+
eq(local(1970,1,1,1,1,50))
|
|
447
|
+
)
|
|
448
|
+
expect(nt('*/10 * * * * *',local(1970,1,1,1,1,49))).to(
|
|
449
|
+
eq(local(1970,1,1,1,1,50))
|
|
450
|
+
)
|
|
451
|
+
expect(nt('*/10 * * * * *',local(1970,1,1,1,1,50))).to(
|
|
452
|
+
eq(local(1970,1,1,1,2,00))
|
|
453
|
+
)
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
describe '#next_second' do
|
|
458
|
+
[
|
|
459
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1, 0), 0 ], # 0 sec to 0s mark
|
|
460
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1, 1), 9 ], # 9 sec to 10s mark
|
|
461
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1, 9), 1 ], # 1 sec to 10s mark
|
|
462
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1,10), 0 ], # 0 sec to 10s mark
|
|
463
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1,11), 9 ], # 9 sec to 20s mark
|
|
464
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1,19), 1 ], # 1 sec to 20s mark
|
|
465
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1,20), 0 ], # 0 sec to 20s mark
|
|
466
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1,21), 9 ], # 1 sec to 30s mark
|
|
467
|
+
# ...
|
|
468
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1,49), 1 ], # 9 sec to 50s mark
|
|
469
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1,50), 0 ], # 0 sec to 50s mark
|
|
470
|
+
[ '*/10 * * * * *', local(1970,1,1,1,1,51), 9 ],
|
|
471
|
+
].each do |cronline, now, sec|
|
|
472
|
+
it "ensures that next_second('#{cronline}', #{now}) is #{sec}" do
|
|
473
|
+
expect(ns(cronline,now)).to eq(sec)
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
describe '#prev_second' do
|
|
479
|
+
|
|
480
|
+
it 'returns the time to the closest previous second' do
|
|
481
|
+
|
|
482
|
+
t = local(1970, 1, 1, 1, 1, 42)
|
|
483
|
+
|
|
484
|
+
expect(ps('35,44 * * * * *', t)).to eq(7)
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
context 'when time sec is lower then all cron seconds (gh-177)' do
|
|
488
|
+
|
|
489
|
+
it 'returns the time to the last second a minute before' do
|
|
490
|
+
|
|
491
|
+
t = local(1970, 1, 1, 1, 1, 42)
|
|
492
|
+
|
|
493
|
+
expect(ps('43,44 * * * * *', t)).to eq(58)
|
|
494
|
+
end
|
|
495
|
+
end
|
|
364
496
|
end
|
|
365
497
|
|
|
366
498
|
describe '#previous_time' do
|
|
@@ -380,6 +512,27 @@ describe Rufus::Scheduler::CronLine do
|
|
|
380
512
|
pt('* * * * * sun', lo(1970, 1, 1))).to eq(lo(1969, 12, 28, 23, 59, 59))
|
|
381
513
|
end
|
|
382
514
|
|
|
515
|
+
it 'jumps to the previous minute if necessary (gh-177)' do
|
|
516
|
+
|
|
517
|
+
t = local(1970, 12, 31, 1, 1, 0) # vanilla
|
|
518
|
+
expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 0, 44))
|
|
519
|
+
|
|
520
|
+
t = local(1970, 12, 31, 1, 1, 30) # 30 < 43 <---- here!
|
|
521
|
+
expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 0, 44))
|
|
522
|
+
|
|
523
|
+
t = local(1970, 12, 31, 1, 1, 43) # 43 <= 43 < 44
|
|
524
|
+
expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 0, 44))
|
|
525
|
+
|
|
526
|
+
t = local(1970, 12, 31, 1, 1, 44) # 44 <= 44
|
|
527
|
+
expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 1, 43))
|
|
528
|
+
|
|
529
|
+
t = local(1970, 12, 31, 1, 1, 59) # 44 < 59
|
|
530
|
+
expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 1, 44))
|
|
531
|
+
|
|
532
|
+
t = local(1970, 12, 31, 1, 1, 30) # a bigger jump
|
|
533
|
+
expect(pt('43,44 10 * * * *', t)).to eq(lo(1970, 12, 31, 0, 10, 44))
|
|
534
|
+
end
|
|
535
|
+
|
|
383
536
|
# New York EST: UTC-5
|
|
384
537
|
# summer (dst) EDT: UTC-4
|
|
385
538
|
|
|
@@ -400,7 +553,10 @@ describe Rufus::Scheduler::CronLine do
|
|
|
400
553
|
'30 1 31 10 * America/New_York',
|
|
401
554
|
ltz('America/New_York', 2004, 10, 31, 14, 30, 0)
|
|
402
555
|
)
|
|
403
|
-
).to eq(
|
|
556
|
+
).to eq(
|
|
557
|
+
ltz('America/New_York', 0, 30, 1, 31, 10, 2004, nil, nil, false, nil)
|
|
558
|
+
# EST time UTC-5
|
|
559
|
+
)
|
|
404
560
|
end
|
|
405
561
|
end
|
|
406
562
|
|
|
@@ -415,6 +571,20 @@ describe Rufus::Scheduler::CronLine do
|
|
|
415
571
|
)
|
|
416
572
|
).to eq(ltz('America/New_York', 2015, 3, 9, 2, 0, 0))
|
|
417
573
|
end
|
|
574
|
+
|
|
575
|
+
it 'computes correctly when * 0,10,20' do
|
|
576
|
+
|
|
577
|
+
expect(
|
|
578
|
+
pt('* 0,10,20 * * *', lo(2000, 1, 1))).to eq(
|
|
579
|
+
lo(1999, 12, 31, 20, 59, 00))
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
it 'computes correctly when * */10' do
|
|
583
|
+
|
|
584
|
+
expect(
|
|
585
|
+
pt('* */10 * * *', lo(2000, 1, 1))).to eq(
|
|
586
|
+
lo(1999, 12, 31, 20, 59, 00))
|
|
587
|
+
end
|
|
418
588
|
end
|
|
419
589
|
|
|
420
590
|
describe '#matches?' do
|
|
@@ -541,6 +711,46 @@ describe Rufus::Scheduler::CronLine do
|
|
|
541
711
|
expect(Rufus::Scheduler::CronLine.new(
|
|
542
712
|
'10,20,30 * * * * *').frequency).to eq(10)
|
|
543
713
|
end
|
|
714
|
+
|
|
715
|
+
it 'spots B-A vs C-B asymmetry in five-field forms' do
|
|
716
|
+
|
|
717
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
718
|
+
'10,17,30 * * * *').frequency).to eq(7 * 60)
|
|
719
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
720
|
+
'10,23,30 * * * *').frequency).to eq(7 * 60)
|
|
721
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
722
|
+
'23,10,30 * * * *').frequency).to eq(7 * 60)
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
it 'spots B-A vs C-B asymmetry in six-field forms' do
|
|
726
|
+
|
|
727
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
728
|
+
'10,17,30 * * * * *').frequency).to eq(7)
|
|
729
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
730
|
+
'10,23,30 * * * * *').frequency).to eq(7)
|
|
731
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
732
|
+
'23,10,30 * * * * *').frequency).to eq(7)
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
it 'handles crontab steps syntax in five-field forms' do
|
|
736
|
+
|
|
737
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
738
|
+
'*/10 * * * *').frequency).to eq(10 * 60)
|
|
739
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
740
|
+
'* */10 * * *').frequency).to eq(60) # "*" all minutes [0..59]
|
|
741
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
742
|
+
'0 */10 * * *').frequency).to eq(4 * 60 * 60) # 2000 to 0000
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
it 'handles crontab steps syntax in six-field forms' do
|
|
746
|
+
|
|
747
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
748
|
+
'*/10 * * * * *').frequency).to eq(10)
|
|
749
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
750
|
+
'* */10 * * * *').frequency).to eq(1) # "*" all seconds [0..59]
|
|
751
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
752
|
+
'0 */10 * * * *').frequency).to eq(10 * 60)
|
|
753
|
+
end
|
|
544
754
|
end
|
|
545
755
|
|
|
546
756
|
describe '#brute_frequency' do
|
|
@@ -572,6 +782,42 @@ describe Rufus::Scheduler::CronLine do
|
|
|
572
782
|
expect(Rufus::Scheduler::CronLine.new(
|
|
573
783
|
'1 2 3 4 5').brute_frequency).to eq(31622400)
|
|
574
784
|
end
|
|
785
|
+
|
|
786
|
+
it 'spots B-A vs C-B asymmetry in five-field forms' do
|
|
787
|
+
|
|
788
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
789
|
+
'10,17,30 * * * *').brute_frequency).to eq(7 * 60)
|
|
790
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
791
|
+
'10,23,30 * * * *').brute_frequency).to eq(7 * 60)
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
it 'spots B-A vs C-B asymmetry in six-field forms' do
|
|
795
|
+
|
|
796
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
797
|
+
'10,17,30 * * * * *').brute_frequency).to eq(7)
|
|
798
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
799
|
+
'10,23,30 * * * * *').brute_frequency).to eq(7)
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
it 'handles crontab modulo syntax in five-field forms' do
|
|
803
|
+
|
|
804
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
805
|
+
'*/10 * * * *').brute_frequency).to eq(10 * 60)
|
|
806
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
807
|
+
'* */10 * * *').brute_frequency).to eq(60) # "*" all minutes [0..59]
|
|
808
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
809
|
+
'0 */10 * * *').brute_frequency).to eq(4 * 60 * 60) # 2000 to 0000
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
it 'handles crontab modulo syntax in six-field forms' do
|
|
813
|
+
|
|
814
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
815
|
+
'*/10 * * * * *').brute_frequency).to eq(10)
|
|
816
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
817
|
+
'* */10 * * * *').brute_frequency).to eq(1) # "*" all seconds [0..59]
|
|
818
|
+
expect(Rufus::Scheduler::CronLine.new(
|
|
819
|
+
'0 */10 * * * *').brute_frequency).to eq(10 * 60)
|
|
820
|
+
end
|
|
575
821
|
end
|
|
576
822
|
|
|
577
823
|
context 'summer time' do
|
|
@@ -678,19 +924,17 @@ describe Rufus::Scheduler::CronLine do
|
|
|
678
924
|
t = Time.local(2015, 3, 8, 1, 57)
|
|
679
925
|
|
|
680
926
|
points =
|
|
681
|
-
|
|
927
|
+
4.times.collect do
|
|
682
928
|
t = line.next_time(t)
|
|
683
|
-
t.
|
|
929
|
+
t.to_compact_s
|
|
684
930
|
end
|
|
685
931
|
|
|
686
|
-
expect(points).to eq(
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
]
|
|
693
|
-
)
|
|
932
|
+
expect(points).to eq([
|
|
933
|
+
'0158-8(0958)',
|
|
934
|
+
'0159-8(0959)',
|
|
935
|
+
'0300-7(1000)',
|
|
936
|
+
'0301-7(1001)'
|
|
937
|
+
])
|
|
694
938
|
end
|
|
695
939
|
end
|
|
696
940
|
|
|
@@ -710,19 +954,158 @@ describe Rufus::Scheduler::CronLine do
|
|
|
710
954
|
t = Time.local(2015, 3, 8, 3, 2)
|
|
711
955
|
|
|
712
956
|
points =
|
|
713
|
-
|
|
957
|
+
4.times.collect do
|
|
714
958
|
t = line.previous_time(t)
|
|
715
|
-
t.
|
|
959
|
+
t.to_compact_s
|
|
716
960
|
end
|
|
717
961
|
|
|
718
|
-
expect(points).to eq(
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
962
|
+
expect(points).to eq([
|
|
963
|
+
'0301-7(1001)',
|
|
964
|
+
'0300-7(1000)',
|
|
965
|
+
'0159-8(0959)',
|
|
966
|
+
'0158-8(0958)'
|
|
967
|
+
])
|
|
968
|
+
end
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
it 'correctly increments when entering DST' do
|
|
972
|
+
|
|
973
|
+
in_zone 'America/Los_Angeles' do
|
|
974
|
+
|
|
975
|
+
line = cl('*/10 * * * * America/Los_Angeles')
|
|
976
|
+
|
|
977
|
+
t = Time.local(2015, 3, 8, 1, 40)
|
|
978
|
+
t1 = t.dup
|
|
979
|
+
|
|
980
|
+
points = []
|
|
981
|
+
while t1 - t < 1 * 3600
|
|
982
|
+
t1 = line.next_time(t1)
|
|
983
|
+
points << t1.to_compact_s
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
expect(points).to eq(%w[
|
|
987
|
+
0150-8(0950)
|
|
988
|
+
0300-7(1000)
|
|
989
|
+
0310-7(1010)
|
|
990
|
+
0320-7(1020)
|
|
991
|
+
0330-7(1030)
|
|
992
|
+
0340-7(1040)
|
|
993
|
+
])
|
|
994
|
+
end
|
|
995
|
+
end
|
|
996
|
+
end
|
|
997
|
+
|
|
998
|
+
context 'fall time' do
|
|
999
|
+
|
|
1000
|
+
it 'correctly increments through a DST transition' do
|
|
1001
|
+
|
|
1002
|
+
expect(
|
|
1003
|
+
nt('* * * * * America/Los_Angeles', Time.utc(2015, 11, 1, 9, 59))
|
|
1004
|
+
).to eq(Time.utc(2015, 11, 1, 10, 00))
|
|
1005
|
+
end
|
|
1006
|
+
|
|
1007
|
+
it 'correctly increments every minute through a DST transition' do
|
|
1008
|
+
|
|
1009
|
+
in_zone 'America/Los_Angeles' do
|
|
1010
|
+
|
|
1011
|
+
line = cl('* * * * * America/Los_Angeles')
|
|
1012
|
+
|
|
1013
|
+
#t = Time.local(2015, 11, 1, 1, 57)
|
|
1014
|
+
#
|
|
1015
|
+
# --> 2015-11-01 01:57:00 -0800 (already PST)
|
|
1016
|
+
|
|
1017
|
+
t = Time.local(0, 57, 1, 1, 11, 2015, nil, nil, true, nil)
|
|
1018
|
+
#
|
|
1019
|
+
# --> 2015-11-01 01:57:00 -0700 (still PDT)
|
|
1020
|
+
|
|
1021
|
+
points =
|
|
1022
|
+
4.times.collect do
|
|
1023
|
+
t = line.next_time(t)
|
|
1024
|
+
t.to_compact_s
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
expect(points).to eq([
|
|
1028
|
+
'0158-7(0858)',
|
|
1029
|
+
'0159-7(0859)',
|
|
1030
|
+
'0100-8(0900)',
|
|
1031
|
+
'0101-8(0901)'
|
|
1032
|
+
])
|
|
1033
|
+
end
|
|
1034
|
+
end
|
|
1035
|
+
|
|
1036
|
+
it 'correctly decrements through a DST transition' do
|
|
1037
|
+
|
|
1038
|
+
expect(
|
|
1039
|
+
pt('* * * * * America/Los_Angeles', Time.utc(2015, 11, 1, 10, 00))
|
|
1040
|
+
).to eq(Time.utc(2015, 11, 1, 9, 59))
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
it 'correctly decrements every minute through a DST transition' do
|
|
1044
|
+
|
|
1045
|
+
in_zone 'America/Los_Angeles' do
|
|
1046
|
+
|
|
1047
|
+
line = cl('* * * * * America/Los_Angeles')
|
|
1048
|
+
|
|
1049
|
+
t = Time.local(0, 2, 1, 1, 11, 2015, nil, nil, true, nil)
|
|
1050
|
+
#
|
|
1051
|
+
# try to force PST
|
|
1052
|
+
|
|
1053
|
+
# TODO: at some point, try to find out if the latest jRuby still
|
|
1054
|
+
# exhibits that behaviour, report to them if necessary
|
|
1055
|
+
|
|
1056
|
+
points =
|
|
1057
|
+
(0..3).collect do
|
|
1058
|
+
t = line.previous_time(t)
|
|
1059
|
+
t.to_compact_s
|
|
1060
|
+
end
|
|
1061
|
+
|
|
1062
|
+
if t.zone == 'PST'
|
|
1063
|
+
expect(points).to eq([
|
|
1064
|
+
'0101-8(0901)',
|
|
1065
|
+
'0100-8(0900)',
|
|
1066
|
+
'0159-7(0859)',
|
|
1067
|
+
'0158-7(0858)'
|
|
1068
|
+
])
|
|
1069
|
+
else
|
|
1070
|
+
expect(points).to eq([
|
|
1071
|
+
'0101-7(0801)',
|
|
1072
|
+
'0100-7(0800)',
|
|
1073
|
+
'0059-7(0759)',
|
|
1074
|
+
'0058-7(0758)'
|
|
1075
|
+
])
|
|
1076
|
+
end
|
|
1077
|
+
end
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
it 'correctly increments when leaving DST' do
|
|
1081
|
+
|
|
1082
|
+
in_zone 'America/Los_Angeles' do
|
|
1083
|
+
|
|
1084
|
+
line = cl('*/10 * * * * America/Los_Angeles')
|
|
1085
|
+
|
|
1086
|
+
t = Time.local(2015, 11, 1, 0, 40)
|
|
1087
|
+
t1 = t.dup
|
|
1088
|
+
|
|
1089
|
+
points = []
|
|
1090
|
+
while t1 - t < 2 * 3600
|
|
1091
|
+
t1 = line.next_time(t1)
|
|
1092
|
+
points << t1.to_compact_s
|
|
1093
|
+
end
|
|
1094
|
+
|
|
1095
|
+
expect(points).to eq([
|
|
1096
|
+
'0050-7(0750)', # | PDT
|
|
1097
|
+
'0100-7(0800)', # |
|
|
1098
|
+
'0110-7(0810)', # V
|
|
1099
|
+
'0120-7(0820)',
|
|
1100
|
+
'0130-7(0830)',
|
|
1101
|
+
'0140-7(0840)',
|
|
1102
|
+
'0150-7(0850)',
|
|
1103
|
+
'0100-8(0900)', # + PST
|
|
1104
|
+
'0110-8(0910)', # |
|
|
1105
|
+
'0120-8(0920)', # V
|
|
1106
|
+
'0130-8(0930)',
|
|
1107
|
+
'0140-8(0940)'
|
|
1108
|
+
])
|
|
726
1109
|
end
|
|
727
1110
|
end
|
|
728
1111
|
end
|
data/spec/job_spec.rb
CHANGED
|
@@ -176,6 +176,16 @@ describe Rufus::Scheduler::Job do
|
|
|
176
176
|
expect(job.running?).to eq(true)
|
|
177
177
|
expect(job.scheduled?).to eq(true)
|
|
178
178
|
end
|
|
179
|
+
|
|
180
|
+
it 'returns false if job is unscheduled' do
|
|
181
|
+
job = @scheduler.schedule_interval('0.1s') { sleep 0.1 }
|
|
182
|
+
job.unschedule
|
|
183
|
+
|
|
184
|
+
sleep 0.3
|
|
185
|
+
|
|
186
|
+
expect(job.running?).to eq(false)
|
|
187
|
+
expect(job.scheduled?).to eq(false)
|
|
188
|
+
end
|
|
179
189
|
end
|
|
180
190
|
|
|
181
191
|
describe '#call' do
|
|
@@ -627,5 +637,35 @@ describe Rufus::Scheduler::Job do
|
|
|
627
637
|
end
|
|
628
638
|
end
|
|
629
639
|
end
|
|
640
|
+
|
|
641
|
+
context 'one time job' do
|
|
642
|
+
|
|
643
|
+
describe '#determine_id' do
|
|
644
|
+
|
|
645
|
+
it 'returns unique ids' do
|
|
646
|
+
|
|
647
|
+
ids = []
|
|
648
|
+
|
|
649
|
+
10_000.times { ids << @scheduler.in('1y') {} }
|
|
650
|
+
|
|
651
|
+
expect(ids.uniq.length).to eq(ids.length)
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
context 'repeat job' do
|
|
657
|
+
|
|
658
|
+
describe '#determine_id' do
|
|
659
|
+
|
|
660
|
+
it 'returns unique ids' do
|
|
661
|
+
|
|
662
|
+
ids = []
|
|
663
|
+
|
|
664
|
+
10_000.times { ids << @scheduler.every('1y') {} }
|
|
665
|
+
|
|
666
|
+
expect(ids.uniq.length).to eq(ids.length)
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
end
|
|
630
670
|
end
|
|
631
671
|
|
data/spec/scheduler_spec.rb
CHANGED
|
@@ -611,7 +611,7 @@ describe Rufus::Scheduler do
|
|
|
611
611
|
end
|
|
612
612
|
end
|
|
613
613
|
|
|
614
|
-
describe '#timeline
|
|
614
|
+
describe '#timeline' do
|
|
615
615
|
|
|
616
616
|
it 'returns a [ [ time, job ], ... ] of job occurrences' do
|
|
617
617
|
|
|
@@ -625,6 +625,21 @@ describe Rufus::Scheduler do
|
|
|
625
625
|
expect(a[1][0]).to be_within_1s_of(Time.now + 10 * 60)
|
|
626
626
|
expect(a[1][1]).to eq(j1)
|
|
627
627
|
end
|
|
628
|
+
|
|
629
|
+
it 'should not lock when running timeline with a :first_at specified' do
|
|
630
|
+
|
|
631
|
+
now = Time.now
|
|
632
|
+
|
|
633
|
+
# scheduling a cron job with a first_at and running #timeline used
|
|
634
|
+
# to result in an infinite loop.
|
|
635
|
+
|
|
636
|
+
@scheduler.cron('* * * * * *', :first_at => now + 3) {}
|
|
637
|
+
|
|
638
|
+
jobs = @scheduler.timeline(now, now + 4)
|
|
639
|
+
expect(jobs.size).to be 2
|
|
640
|
+
expect(jobs[0][0]).to be_within_1s_of now + 3
|
|
641
|
+
expect(jobs[1][0]).to be_within_1s_of now + 4
|
|
642
|
+
end
|
|
628
643
|
end
|
|
629
644
|
|
|
630
645
|
#--
|
data/spec/spec_helper.rb
CHANGED
data/spec/zotime_spec.rb
CHANGED
|
@@ -73,22 +73,17 @@ describe Rufus::Scheduler::ZoTime do
|
|
|
73
73
|
# New York EST: UTC-5
|
|
74
74
|
# summer (dst) EDT: UTC-4
|
|
75
75
|
|
|
76
|
-
it 'chooses the
|
|
76
|
+
it 'chooses the DST time when there is ambiguity' do
|
|
77
77
|
|
|
78
78
|
t = ltz('America/New_York', 2004, 10, 31, 0, 30, 0)
|
|
79
79
|
zt = Rufus::Scheduler::ZoTime.new(t, 'America/New_York')
|
|
80
80
|
zt.add(3600)
|
|
81
81
|
ztt = zt.time
|
|
82
82
|
|
|
83
|
-
expect(ztt.to_i).to eq(1099204200)
|
|
83
|
+
expect(ztt.to_i).to eq(1099204200 - 3600)
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
).to eq('2004/10/31 01:30:00 EST -0500')
|
|
88
|
-
else
|
|
89
|
-
expect(ztt.strftime('%Y/%m/%d %H:%M:%S %Z %z')
|
|
90
|
-
).to eq('2004/10/31 01:30:00 EST -0500')
|
|
91
|
-
end
|
|
85
|
+
expect(ztt.strftime('%Y/%m/%d %H:%M:%S %Z %z')
|
|
86
|
+
).to eq('2004/10/31 01:30:00 EDT -0400')
|
|
92
87
|
end
|
|
93
88
|
end
|
|
94
89
|
|
|
@@ -162,17 +157,17 @@ describe Rufus::Scheduler::ZoTime do
|
|
|
162
157
|
st3 = t3.strftime('%Y/%m/%d %H:%M:%S %Z') + " #{t3.isdst}"
|
|
163
158
|
|
|
164
159
|
expect(t0.to_i).to eq(1414281599)
|
|
165
|
-
expect(t1.to_i).to eq(1414285200)
|
|
160
|
+
expect(t1.to_i).to eq(1414285200 - 3600)
|
|
166
161
|
expect(t2.to_i).to eq(1414285200)
|
|
167
162
|
expect(t3.to_i).to eq(1414285201)
|
|
168
163
|
|
|
169
164
|
expect(st0).to eq('2014/10/26 01:59:59 CEST true')
|
|
170
|
-
expect(st1).to eq('2014/10/26 02:00:00
|
|
165
|
+
expect(st1).to eq('2014/10/26 02:00:00 CEST true')
|
|
171
166
|
expect(st2).to eq('2014/10/26 02:00:00 CET false')
|
|
172
167
|
expect(st3).to eq('2014/10/26 02:00:01 CET false')
|
|
173
168
|
|
|
174
|
-
expect(t1 - t0).to eq(
|
|
175
|
-
expect(t2 - t1).to eq(
|
|
169
|
+
expect(t1 - t0).to eq(1)
|
|
170
|
+
expect(t2 - t1).to eq(3600)
|
|
176
171
|
expect(t3 - t2).to eq(1)
|
|
177
172
|
end
|
|
178
173
|
end
|
data/t.txt
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
JRUBY
|
|
3
|
+
|
|
4
|
+
1) Rufus::Scheduler::CronLine fall time correctly decrements every minute through a DST transition
|
|
5
|
+
|
|
6
|
+
Failure/Error: expect(points).to eq([
|
|
7
|
+
|
|
8
|
+
expected: ["0101-8(0901)", "0100-8(0900)", "0159-7(0859)", "0158-7(0858)"]
|
|
9
|
+
got: ["0101-7(0801)", "0100-7(0800)", "0059-7(0759)", "0058-7(0758)"]
|
|
10
|
+
|
|
11
|
+
(compared using ==)
|
|
12
|
+
# ./spec/cronline_spec.rb:1013:in `(root)'
|
|
13
|
+
# ./spec/spec_helper.rb:69:in `in_zone'
|
|
14
|
+
# ./spec/cronline_spec.rb:1001:in `(root)'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
RUBY1.8
|
|
18
|
+
|
|
19
|
+
1) Rufus::Scheduler::CronLine fall time correctly decrements every minute through a DST transition
|
|
20
|
+
|
|
21
|
+
Failure/Error: expect(points).to eq([
|
|
22
|
+
|
|
23
|
+
expected: ["0101-8(0901)", "0100-8(0900)", "0159-7(0859)", "0158-7(0858)"]
|
|
24
|
+
got: ["0101-7(0801)", "0100-7(0800)", "0059-7(0759)", "0058-7(0758)"]
|
|
25
|
+
|
|
26
|
+
(compared using ==)
|
|
27
|
+
# ./spec/cronline_spec.rb:1013
|
|
28
|
+
# ./spec/spec_helper.rb:69:in `call'
|
|
29
|
+
# ./spec/spec_helper.rb:69:in `in_zone'
|
|
30
|
+
# ./spec/cronline_spec.rb:1001
|
|
31
|
+
|
metadata
CHANGED
|
@@ -1,78 +1,69 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rufus-scheduler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.1.
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 3.1.9
|
|
6
5
|
platform: ruby
|
|
7
6
|
authors:
|
|
8
7
|
- John Mettraux
|
|
9
8
|
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date: 2015-
|
|
11
|
+
date: 2015-11-11 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: rake
|
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
|
17
|
-
none: false
|
|
18
16
|
requirements:
|
|
19
|
-
- -
|
|
17
|
+
- - ">="
|
|
20
18
|
- !ruby/object:Gem::Version
|
|
21
19
|
version: '0'
|
|
22
20
|
type: :development
|
|
23
21
|
prerelease: false
|
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
-
none: false
|
|
26
23
|
requirements:
|
|
27
|
-
- -
|
|
24
|
+
- - ">="
|
|
28
25
|
- !ruby/object:Gem::Version
|
|
29
26
|
version: '0'
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
|
31
28
|
name: rspec
|
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
|
33
|
-
none: false
|
|
34
30
|
requirements:
|
|
35
|
-
- -
|
|
31
|
+
- - ">="
|
|
36
32
|
- !ruby/object:Gem::Version
|
|
37
33
|
version: 2.13.0
|
|
38
34
|
type: :development
|
|
39
35
|
prerelease: false
|
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
-
none: false
|
|
42
37
|
requirements:
|
|
43
|
-
- -
|
|
38
|
+
- - ">="
|
|
44
39
|
- !ruby/object:Gem::Version
|
|
45
40
|
version: 2.13.0
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
|
47
42
|
name: chronic
|
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
|
49
|
-
none: false
|
|
50
44
|
requirements:
|
|
51
|
-
- -
|
|
45
|
+
- - ">="
|
|
52
46
|
- !ruby/object:Gem::Version
|
|
53
47
|
version: '0'
|
|
54
48
|
type: :development
|
|
55
49
|
prerelease: false
|
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
-
none: false
|
|
58
51
|
requirements:
|
|
59
|
-
- -
|
|
52
|
+
- - ">="
|
|
60
53
|
- !ruby/object:Gem::Version
|
|
61
54
|
version: '0'
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
|
63
56
|
name: tzinfo
|
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
|
65
|
-
none: false
|
|
66
58
|
requirements:
|
|
67
|
-
- -
|
|
59
|
+
- - ">="
|
|
68
60
|
- !ruby/object:Gem::Version
|
|
69
61
|
version: '0'
|
|
70
62
|
type: :development
|
|
71
63
|
prerelease: false
|
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
-
none: false
|
|
74
65
|
requirements:
|
|
75
|
-
- -
|
|
66
|
+
- - ">="
|
|
76
67
|
- !ruby/object:Gem::Version
|
|
77
68
|
version: '0'
|
|
78
69
|
description: job scheduler for Ruby (at, cron, in and every jobs).
|
|
@@ -82,70 +73,70 @@ executables: []
|
|
|
82
73
|
extensions: []
|
|
83
74
|
extra_rdoc_files: []
|
|
84
75
|
files:
|
|
76
|
+
- CHANGELOG.txt
|
|
77
|
+
- CREDITS.txt
|
|
78
|
+
- LICENSE.txt
|
|
79
|
+
- README.md
|
|
85
80
|
- Rakefile
|
|
81
|
+
- TODO.txt
|
|
86
82
|
- lib/rufus-scheduler.rb
|
|
87
83
|
- lib/rufus/scheduler.rb
|
|
88
|
-
- lib/rufus/scheduler/locks.rb
|
|
89
|
-
- lib/rufus/scheduler/zotime.rb
|
|
90
84
|
- lib/rufus/scheduler/cronline.rb
|
|
91
|
-
- lib/rufus/scheduler/
|
|
85
|
+
- lib/rufus/scheduler/job_array.rb
|
|
92
86
|
- lib/rufus/scheduler/jobs.rb
|
|
87
|
+
- lib/rufus/scheduler/locks.rb
|
|
88
|
+
- lib/rufus/scheduler/util.rb
|
|
93
89
|
- lib/rufus/scheduler/zones.rb
|
|
94
|
-
- lib/rufus/scheduler/
|
|
95
|
-
-
|
|
96
|
-
- spec/
|
|
97
|
-
- spec/
|
|
98
|
-
- spec/
|
|
90
|
+
- lib/rufus/scheduler/zotime.rb
|
|
91
|
+
- rufus-scheduler.gemspec
|
|
92
|
+
- spec/basics_spec.rb
|
|
93
|
+
- spec/cronline_spec.rb
|
|
94
|
+
- spec/error_spec.rb
|
|
99
95
|
- spec/job_array_spec.rb
|
|
100
|
-
- spec/schedule_interval_spec.rb
|
|
101
96
|
- spec/job_at_spec.rb
|
|
102
|
-
- spec/
|
|
103
|
-
- spec/
|
|
104
|
-
- spec/
|
|
105
|
-
- spec/schedule_cron_spec.rb
|
|
97
|
+
- spec/job_cron_spec.rb
|
|
98
|
+
- spec/job_every_spec.rb
|
|
99
|
+
- spec/job_in_spec.rb
|
|
106
100
|
- spec/job_interval_spec.rb
|
|
107
101
|
- spec/job_repeat_spec.rb
|
|
108
|
-
- spec/
|
|
109
|
-
- spec/
|
|
110
|
-
- spec/
|
|
102
|
+
- spec/job_spec.rb
|
|
103
|
+
- spec/lock_custom_spec.rb
|
|
104
|
+
- spec/lock_flock_spec.rb
|
|
111
105
|
- spec/lock_lockfile_spec.rb
|
|
112
|
-
- spec/
|
|
106
|
+
- spec/lock_spec.rb
|
|
113
107
|
- spec/parse_spec.rb
|
|
108
|
+
- spec/schedule_at_spec.rb
|
|
109
|
+
- spec/schedule_cron_spec.rb
|
|
110
|
+
- spec/schedule_every_spec.rb
|
|
111
|
+
- spec/schedule_in_spec.rb
|
|
112
|
+
- spec/schedule_interval_spec.rb
|
|
114
113
|
- spec/scheduler_spec.rb
|
|
115
|
-
- spec/
|
|
116
|
-
- spec/
|
|
117
|
-
- spec/
|
|
118
|
-
-
|
|
119
|
-
- spec/lock_flock_spec.rb
|
|
120
|
-
- rufus-scheduler.gemspec
|
|
121
|
-
- CHANGELOG.txt
|
|
122
|
-
- TODO.txt
|
|
123
|
-
- LICENSE.txt
|
|
124
|
-
- CREDITS.txt
|
|
125
|
-
- README.md
|
|
114
|
+
- spec/spec_helper.rb
|
|
115
|
+
- spec/threads_spec.rb
|
|
116
|
+
- spec/zotime_spec.rb
|
|
117
|
+
- t.txt
|
|
126
118
|
homepage: http://github.com/jmettraux/rufus-scheduler
|
|
127
119
|
licenses:
|
|
128
120
|
- MIT
|
|
121
|
+
metadata: {}
|
|
129
122
|
post_install_message:
|
|
130
123
|
rdoc_options: []
|
|
131
124
|
require_paths:
|
|
132
125
|
- lib
|
|
133
126
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
134
|
-
none: false
|
|
135
127
|
requirements:
|
|
136
|
-
- -
|
|
128
|
+
- - ">="
|
|
137
129
|
- !ruby/object:Gem::Version
|
|
138
130
|
version: '0'
|
|
139
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
|
-
none: false
|
|
141
132
|
requirements:
|
|
142
|
-
- -
|
|
133
|
+
- - ">="
|
|
143
134
|
- !ruby/object:Gem::Version
|
|
144
135
|
version: '0'
|
|
145
136
|
requirements: []
|
|
146
137
|
rubyforge_project: rufus
|
|
147
|
-
rubygems_version:
|
|
138
|
+
rubygems_version: 2.2.2
|
|
148
139
|
signing_key:
|
|
149
|
-
specification_version:
|
|
140
|
+
specification_version: 4
|
|
150
141
|
summary: job scheduler for Ruby (at, cron, in and every jobs)
|
|
151
142
|
test_files: []
|