rufus-scheduler 3.2.2 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +8 -0
- data/CREDITS.txt +4 -0
- data/README.md +9 -1
- data/fail18.txt +12 -0
- data/lib/rufus/scheduler.rb +9 -8
- data/lib/rufus/scheduler/cronline.rb +71 -71
- data/lib/rufus/scheduler/job_array.rb +7 -3
- data/lib/rufus/scheduler/jobs.rb +50 -34
- data/lib/rufus/scheduler/util.rb +19 -20
- data/lib/rufus/scheduler/zotime.rb +347 -65
- data/pics.txt +15 -0
- data/rufus-scheduler.gemspec +1 -2
- metadata +28 -27
- data/lib/rufus/scheduler/zones.rb +0 -175
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5efdaec8fd127103673241abfcb7a14d9135aef
|
4
|
+
data.tar.gz: 95b4b8f72eaea194b946e9b6738fa42b9086fc2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d511d09f4a9c0deffd90a97005d0824b891a55a92236cf885fde676830960ebbaad407d1a4fd4817b81d20d0f7ef9a504ad35b96a58b7a195e30bae89eda0046
|
7
|
+
data.tar.gz: d4da5209b9d01d6a4c861ed022b36971377762ae31ec785d068c0070af3e098e0ff0f6939cd128a96f5752deb74c49daf798a074d6a7557fa80d125f4286dcd5
|
data/CHANGELOG.txt
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
+
== rufus-scheduler - 3.3.0 released 2016-11-28
|
6
|
+
|
7
|
+
- Bring in Piavka's Job#trigger_off_schedule, gh-214
|
8
|
+
- Reject "day 0" in cronlines, thanks to Ramon Tayag, https://github.com/ramontayag
|
9
|
+
- Move away from ENV['TZ'], thanks to Akinori Musha, https://github.com/knu
|
10
|
+
- Fix .parse_to_time vs Date issue, as reported by @nsatragno
|
11
|
+
|
12
|
+
|
5
13
|
== rufus-scheduler - 3.2.2 released 2016-08-14
|
6
14
|
|
7
15
|
- job opt hash preservation, as suggested in gh-212, by https://github.com/d-m-u
|
data/CREDITS.txt
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
== Contributors
|
6
6
|
|
7
|
+
- Piavka (https://github.com/piavka) - Job#trigger_off_schedule, gh-214
|
7
8
|
- Paulo Delgado (https://github.com/paulodelgado) counter ActiveRecord, gh-210
|
8
9
|
- Anjali Sharma (https://github.com/anjali-sharma) enhance job#last_time example
|
9
10
|
- Kyle Simukka (https://github.com/simook) raise on "*/0 * * * *"
|
@@ -50,6 +51,9 @@
|
|
50
51
|
|
51
52
|
== Feedback
|
52
53
|
|
54
|
+
- Ramon Tayag - https://github.com/ramontayag - prevent day 0 in cronlines
|
55
|
+
- Akinori Musha - https://github.com/knu - ENV['TZ'] setting is harmful
|
56
|
+
- Nicolás Satragno - https://twitter.com/nsatragno - parse_to_time vs Date
|
53
57
|
- d-m-u duhlmann - https://github.com/d-m-u - job opt hash preservation
|
54
58
|
- Anjali Sharma - https://github.com/anjali-sharma - fix typographical error
|
55
59
|
- Jonathan Campos - https://github.com/jonbcampos - negative cron day idea
|
data/README.md
CHANGED
@@ -6,6 +6,8 @@
|
|
6
6
|
|
7
7
|
Job scheduler for Ruby (at, cron, in and every jobs).
|
8
8
|
|
9
|
+
It uses threads.
|
10
|
+
|
9
11
|
**Note**: maybe are you looking for the [README of rufus-scheduler 2.x](https://github.com/jmettraux/rufus-scheduler/blob/two/README.rdoc)?
|
10
12
|
|
11
13
|
Quickstart:
|
@@ -55,10 +57,12 @@ end
|
|
55
57
|
|
56
58
|
## non-features
|
57
59
|
|
58
|
-
Rufus-scheduler (out of the box) is an in-process, in-memory scheduler.
|
60
|
+
Rufus-scheduler (out of the box) is an in-process, in-memory scheduler. It uses threads.
|
59
61
|
|
60
62
|
It does not persist your schedules. When the process is gone and the scheduler instance with it, the schedules are gone.
|
61
63
|
|
64
|
+
A rufus-scheduler instance will go on scheduling while it is present among the object in a Ruby process. To make it stop scheduling you have to call its [`#shutdown` method](#schedulershutdown).
|
65
|
+
|
62
66
|
|
63
67
|
## related and similar gems
|
64
68
|
|
@@ -371,6 +375,8 @@ Since, by default, jobs are triggered in their own new thread, job instances mig
|
|
371
375
|
|
372
376
|
To prevent overlap, one can set :overlap => false. Such a job will not trigger if one of its instance is already running.
|
373
377
|
|
378
|
+
The `:overlap` option is considered before the `:mutex` option when the scheduler is reviewing jobs for triggering.
|
379
|
+
|
374
380
|
### :mutex => mutex_instance / mutex_name / array of mutexes
|
375
381
|
|
376
382
|
When a job with a mutex triggers, the job's block is executed with the mutex around it, preventing other jobs with the same mutex to enter (it makes the other jobs wait until it exits the mutex).
|
@@ -383,6 +389,8 @@ Array of mutexes: original idea and implementation by [Rainux Luo](https://githu
|
|
383
389
|
|
384
390
|
Warning: creating lots of different mutexes is OK. Rufus-scheduler will place them in its Scheduler#mutexes hash... And they won't get garbage collected.
|
385
391
|
|
392
|
+
The `:overlap` option is considered before the `:mutex` option when the scheduler is reviewing jobs for triggering.
|
393
|
+
|
386
394
|
### :timeout => duration or point in time
|
387
395
|
|
388
396
|
It's OK to specify a timeout when scheduling some work. After the time specified, it gets interrupted via a Rufus::Scheduler::TimeoutError.
|
data/fail18.txt
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
rspec ./spec/job_spec.rb:640 # Rufus::Scheduler::Job work time #mean_work_time gathers work times and computes the mean
|
3
|
+
rspec ./spec/schedule_at_spec.rb:60 # Rufus::Scheduler#at triggers a job
|
4
|
+
rspec ./spec/schedule_in_spec.rb:44 # Rufus::Scheduler#in removes the job after execution
|
5
|
+
rspec ./spec/scheduler_spec.rb:83 # Rufus::Scheduler a schedule method passes the job to its block when it triggers
|
6
|
+
rspec ./spec/scheduler_spec.rb:534 # Rufus::Scheduler#running_jobs(:tag/:tags => x) returns a list of running jobs filtered by tag
|
7
|
+
rspec ./spec/scheduler_spec.rb:601 # Rufus::Scheduler#occurrences(time0, time1) respects :times for repeat jobs
|
8
|
+
rspec ./spec/scheduler_spec.rb:1019 # Rufus::Scheduler#on_post_trigger is called right after a job triggers
|
9
|
+
|
10
|
+
|
11
|
+
determine_id specs are slower... much slower...
|
12
|
+
|
data/lib/rufus/scheduler.rb
CHANGED
@@ -25,7 +25,7 @@
|
|
25
25
|
require 'date' if RUBY_VERSION < '1.9.0'
|
26
26
|
require 'time'
|
27
27
|
require 'thread'
|
28
|
-
|
28
|
+
require 'tzinfo'
|
29
29
|
|
30
30
|
|
31
31
|
module Rufus
|
@@ -39,7 +39,7 @@ module Rufus
|
|
39
39
|
require 'rufus/scheduler/job_array'
|
40
40
|
require 'rufus/scheduler/locks'
|
41
41
|
|
42
|
-
VERSION = '3.
|
42
|
+
VERSION = '3.3.0'
|
43
43
|
|
44
44
|
#
|
45
45
|
# A common error class for rufus-scheduler
|
@@ -154,7 +154,7 @@ module Rufus
|
|
154
154
|
|
155
155
|
def uptime
|
156
156
|
|
157
|
-
@started_at ?
|
157
|
+
@started_at ? Rufus::Scheduler::ZoTime.now - @started_at : nil
|
158
158
|
end
|
159
159
|
|
160
160
|
def uptime_s
|
@@ -478,6 +478,7 @@ module Rufus
|
|
478
478
|
stderr.puts(" #{pre} tz:")
|
479
479
|
stderr.puts(" #{pre} ENV['TZ']: #{ENV['TZ']}")
|
480
480
|
stderr.puts(" #{pre} Time.now: #{Time.now}")
|
481
|
+
stderr.puts(" #{pre} local_tzone: #{Rufus::Scheduler::ZoTime.local_tzone.inspect}")
|
481
482
|
stderr.puts(" #{pre} scheduler:")
|
482
483
|
stderr.puts(" #{pre} object_id: #{object_id}")
|
483
484
|
stderr.puts(" #{pre} opts:")
|
@@ -557,7 +558,7 @@ module Rufus
|
|
557
558
|
|
558
559
|
def start
|
559
560
|
|
560
|
-
@started_at =
|
561
|
+
@started_at = Rufus::Scheduler::ZoTime.now
|
561
562
|
|
562
563
|
@thread =
|
563
564
|
Thread.new do
|
@@ -584,7 +585,7 @@ module Rufus
|
|
584
585
|
|
585
586
|
def trigger_jobs
|
586
587
|
|
587
|
-
now =
|
588
|
+
now = Rufus::Scheduler::ZoTime.now
|
588
589
|
|
589
590
|
@jobs.each(now) do |job|
|
590
591
|
|
@@ -603,9 +604,9 @@ module Rufus
|
|
603
604
|
next unless job && to && ts
|
604
605
|
# thread might just have become inactive (job -> nil)
|
605
606
|
|
606
|
-
to = to.is_a?(
|
607
|
+
to = ts + to unless to.is_a?(Rufus::Scheduler::ZoTime)
|
607
608
|
|
608
|
-
next if to >
|
609
|
+
next if to > Rufus::Scheduler::ZoTime.now
|
609
610
|
|
610
611
|
t.raise(Rufus::Scheduler::TimeoutError)
|
611
612
|
end
|
@@ -626,7 +627,7 @@ module Rufus
|
|
626
627
|
case job_type
|
627
628
|
when :once
|
628
629
|
opts[:_t] ||= Rufus::Scheduler.parse(t, opts)
|
629
|
-
opts[:_t].is_a?(
|
630
|
+
opts[:_t].is_a?(Numeric) ? InJob : AtJob
|
630
631
|
when :every
|
631
632
|
EveryJob
|
632
633
|
when :interval
|
@@ -36,6 +36,7 @@ class Rufus::Scheduler
|
|
36
36
|
# The string used for creating this cronline instance.
|
37
37
|
#
|
38
38
|
attr_reader :original
|
39
|
+
attr_reader :original_timezone
|
39
40
|
|
40
41
|
attr_reader :seconds
|
41
42
|
attr_reader :minutes
|
@@ -53,10 +54,15 @@ class Rufus::Scheduler
|
|
53
54
|
) unless line.is_a?(String)
|
54
55
|
|
55
56
|
@original = line
|
57
|
+
@original_timezone = nil
|
56
58
|
|
57
59
|
items = line.split
|
58
60
|
|
59
|
-
@timezone =
|
61
|
+
if @timezone = ZoTime.get_tzone(items.last)
|
62
|
+
@original_timezone = items.pop
|
63
|
+
else
|
64
|
+
@timezone = ZoTime.get_tzone(:current)
|
65
|
+
end
|
60
66
|
|
61
67
|
fail ArgumentError.new(
|
62
68
|
"not a valid cronline : '#{line}'"
|
@@ -77,18 +83,26 @@ class Rufus::Scheduler
|
|
77
83
|
"invalid cronline: '#{line}'"
|
78
84
|
) if es && es.find { |e| ! e.is_a?(Fixnum) }
|
79
85
|
end
|
86
|
+
|
87
|
+
if @days && @days.include?(0) # gh-221
|
88
|
+
|
89
|
+
fail ArgumentError.new('invalid day 0 in cronline')
|
90
|
+
end
|
80
91
|
end
|
81
92
|
|
82
93
|
# Returns true if the given time matches this cron line.
|
83
94
|
#
|
84
95
|
def matches?(time)
|
85
96
|
|
86
|
-
|
97
|
+
# FIXME Don't create a new ZoTime if time is already a ZoTime in same
|
98
|
+
# zone ...
|
99
|
+
# Wait, this seems only used in specs...
|
100
|
+
t = ZoTime.new(time.to_f, @timezone)
|
87
101
|
|
88
|
-
return false unless sub_match?(
|
89
|
-
return false unless sub_match?(
|
90
|
-
return false unless sub_match?(
|
91
|
-
return false unless date_match?(
|
102
|
+
return false unless sub_match?(t, :sec, @seconds)
|
103
|
+
return false unless sub_match?(t, :min, @minutes)
|
104
|
+
return false unless sub_match?(t, :hour, @hours)
|
105
|
+
return false unless date_match?(t)
|
92
106
|
true
|
93
107
|
end
|
94
108
|
|
@@ -119,36 +133,36 @@ class Rufus::Scheduler
|
|
119
133
|
#
|
120
134
|
# (Thanks to K Liu for the note and the examples)
|
121
135
|
#
|
122
|
-
def next_time(from=
|
136
|
+
def next_time(from=ZoTime.now)
|
123
137
|
|
124
|
-
|
125
|
-
|
138
|
+
nt = nil
|
139
|
+
zt = ZoTime.new(from.to_i + 1, @timezone)
|
126
140
|
|
127
141
|
loop do
|
128
142
|
|
129
|
-
|
143
|
+
nt = zt.dup
|
130
144
|
|
131
|
-
unless date_match?(
|
132
|
-
|
145
|
+
unless date_match?(nt)
|
146
|
+
zt.add((24 - nt.hour) * 3600 - nt.min * 60 - nt.sec)
|
133
147
|
next
|
134
148
|
end
|
135
|
-
unless sub_match?(
|
136
|
-
|
149
|
+
unless sub_match?(nt, :hour, @hours)
|
150
|
+
zt.add((60 - nt.min) * 60 - nt.sec)
|
137
151
|
next
|
138
152
|
end
|
139
|
-
unless sub_match?(
|
140
|
-
|
153
|
+
unless sub_match?(nt, :min, @minutes)
|
154
|
+
zt.add(60 - nt.sec)
|
141
155
|
next
|
142
156
|
end
|
143
|
-
unless sub_match?(
|
144
|
-
|
157
|
+
unless sub_match?(nt, :sec, @seconds)
|
158
|
+
zt.add(next_second(nt))
|
145
159
|
next
|
146
160
|
end
|
147
161
|
|
148
162
|
break
|
149
163
|
end
|
150
164
|
|
151
|
-
|
165
|
+
nt
|
152
166
|
end
|
153
167
|
|
154
168
|
# Returns the previous time the cronline matched. It's like next_time, but
|
@@ -156,34 +170,34 @@ class Rufus::Scheduler
|
|
156
170
|
#
|
157
171
|
def previous_time(from=Time.now)
|
158
172
|
|
159
|
-
|
160
|
-
|
173
|
+
pt = nil
|
174
|
+
zt = ZoTime.new(from.to_i - 1, @timezone)
|
161
175
|
|
162
176
|
loop do
|
163
177
|
|
164
|
-
|
178
|
+
pt = zt.dup
|
165
179
|
|
166
|
-
unless date_match?(
|
167
|
-
|
180
|
+
unless date_match?(pt)
|
181
|
+
zt.substract(pt.hour * 3600 + pt.min * 60 + pt.sec + 1)
|
168
182
|
next
|
169
183
|
end
|
170
|
-
unless sub_match?(
|
171
|
-
|
184
|
+
unless sub_match?(pt, :hour, @hours)
|
185
|
+
zt.substract(pt.min * 60 + pt.sec + 1)
|
172
186
|
next
|
173
187
|
end
|
174
|
-
unless sub_match?(
|
175
|
-
|
188
|
+
unless sub_match?(pt, :min, @minutes)
|
189
|
+
zt.substract(pt.sec + 1)
|
176
190
|
next
|
177
191
|
end
|
178
|
-
unless sub_match?(
|
179
|
-
|
192
|
+
unless sub_match?(pt, :sec, @seconds)
|
193
|
+
zt.substract(prev_second(pt))
|
180
194
|
next
|
181
195
|
end
|
182
196
|
|
183
197
|
break
|
184
198
|
end
|
185
199
|
|
186
|
-
|
200
|
+
pt
|
187
201
|
end
|
188
202
|
|
189
203
|
# Returns an array of 6 arrays (seconds, minutes, hours, days,
|
@@ -200,7 +214,7 @@ class Rufus::Scheduler
|
|
200
214
|
toa(@months),
|
201
215
|
toa(@weekdays),
|
202
216
|
toa(@monthdays),
|
203
|
-
@timezone
|
217
|
+
@timezone.name
|
204
218
|
]
|
205
219
|
end
|
206
220
|
alias to_array to_a
|
@@ -260,7 +274,9 @@ class Rufus::Scheduler
|
|
260
274
|
break if delta <= 1
|
261
275
|
break if delta <= 60 && @seconds && @seconds.size == 1
|
262
276
|
|
277
|
+
#st = Time.now
|
263
278
|
t1 = next_time(t0)
|
279
|
+
#p Time.now - st
|
264
280
|
d = t1 - t0
|
265
281
|
delta = d if d < delta
|
266
282
|
|
@@ -314,7 +330,6 @@ class Rufus::Scheduler
|
|
314
330
|
|
315
331
|
WEEKDAYS = %w[ sun mon tue wed thu fri sat ]
|
316
332
|
DAY_S = 24 * 3600
|
317
|
-
WEEK_S = 7 * DAY_S
|
318
333
|
|
319
334
|
def parse_weekdays(item)
|
320
335
|
|
@@ -431,12 +446,14 @@ class Rufus::Scheduler
|
|
431
446
|
r.uniq
|
432
447
|
end
|
433
448
|
|
449
|
+
# FIXME: Eventually split into day_match?, hour_match? and monthdays_match?o
|
450
|
+
#
|
434
451
|
def sub_match?(time, accessor, values)
|
435
452
|
|
436
|
-
value = time.send(accessor)
|
437
|
-
|
438
453
|
return true if values.nil?
|
439
454
|
|
455
|
+
value = time.send(accessor)
|
456
|
+
|
440
457
|
if accessor == :day
|
441
458
|
|
442
459
|
values.each do |v|
|
@@ -450,48 +467,31 @@ class Rufus::Scheduler
|
|
450
467
|
return true if value == 0 && values.include?(24)
|
451
468
|
end
|
452
469
|
|
453
|
-
|
454
|
-
end
|
455
|
-
|
456
|
-
def monthday_match?(date, values)
|
470
|
+
if accessor == :monthdays
|
457
471
|
|
458
|
-
|
459
|
-
|
460
|
-
today_values = monthdays(date)
|
461
|
-
|
462
|
-
(today_values & values).any?
|
463
|
-
end
|
464
|
-
|
465
|
-
def date_match?(date)
|
472
|
+
return true if (values & value).any?
|
473
|
+
end
|
466
474
|
|
467
|
-
|
468
|
-
return false unless sub_match?(date, :month, @months)
|
469
|
-
return false unless sub_match?(date, :wday, @weekdays)
|
470
|
-
return false unless monthday_match?(date, @monthdays)
|
471
|
-
true
|
475
|
+
values.include?(value)
|
472
476
|
end
|
473
477
|
|
474
|
-
def
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
pos = pos + 1
|
483
|
-
end
|
478
|
+
# def monthday_match?(zt, values)
|
479
|
+
#
|
480
|
+
# return true if values.nil?
|
481
|
+
#
|
482
|
+
# today_values = monthdays(zt)
|
483
|
+
#
|
484
|
+
# (today_values & values).any?
|
485
|
+
# end
|
484
486
|
|
485
|
-
|
486
|
-
d = date.dup
|
487
|
+
def date_match?(zt)
|
487
488
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
[ "#{date.wday}##{pos}", "#{date.wday}##{neg}" ]
|
489
|
+
return false unless sub_match?(zt, :day, @days)
|
490
|
+
return false unless sub_match?(zt, :month, @months)
|
491
|
+
return false unless sub_match?(zt, :wday, @weekdays)
|
492
|
+
#return false unless monthday_match?(zt, @monthdays)
|
493
|
+
return false unless sub_match?(zt, :monthdays, @monthdays)
|
494
|
+
true
|
495
495
|
end
|
496
496
|
end
|
497
497
|
end
|
@@ -53,10 +53,14 @@ module Rufus
|
|
53
53
|
|
54
54
|
def each(now, &block)
|
55
55
|
|
56
|
-
to_a.sort_by
|
56
|
+
to_a.sort_by do |job|
|
57
57
|
|
58
|
-
|
59
|
-
|
58
|
+
job.next_time || (now + 1)
|
59
|
+
|
60
|
+
end.each do |job|
|
61
|
+
|
62
|
+
nt = job.next_time
|
63
|
+
break if ( ! nt) || (nt > now)
|
60
64
|
|
61
65
|
block.call(job)
|
62
66
|
end
|