rufus-scheduler 2.0.18 → 2.0.19
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +7 -1
- data/CREDITS.txt +2 -0
- data/README.rdoc +40 -0
- data/lib/rufus/sc/jobs.rb +10 -5
- data/lib/rufus/sc/rtime.rb +5 -0
- data/lib/rufus/sc/scheduler.rb +16 -4
- data/lib/rufus/sc/version.rb +1 -1
- data/out.txt +4 -0
- data/spec/every_spec.rb +45 -0
- data/spec/job_spec.rb +1 -1
- data/spec/mutex_spec.rb +66 -0
- data/spec/rtime_spec.rb +17 -0
- metadata +27 -26
data/CHANGELOG.txt
CHANGED
@@ -2,7 +2,13 @@
|
|
2
2
|
= rufus-scheduler CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
-
== rufus-scheduler - 2.0.
|
5
|
+
== rufus-scheduler - 2.0.19 released 2013/05/07
|
6
|
+
|
7
|
+
- raise ArgumentError on <= 0.0 "every" frequency (Thanks Lucy Fu)
|
8
|
+
- support multiple mutexes (Thanks Rainux Luo)
|
9
|
+
|
10
|
+
|
11
|
+
== rufus-scheduler - 2.0.18 released 2013/03/06
|
6
12
|
|
7
13
|
- support for "L" in cron lines (Thanks Andrew Davey)
|
8
14
|
- support for negative time strings (Thanks Danny "northox" Fullerton)
|
data/CREDITS.txt
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
== Contributors
|
6
6
|
|
7
|
+
- Lucy Fu (https://github.com/lfu) arg error on <= 0 "every" freq
|
8
|
+
- Rainux Luo (https://github.com/rainux) multiple mutexes
|
7
9
|
- Andrew Davey (https://github.com/asdavey) "L" in cron lines
|
8
10
|
- Stig Kleppe-Jørgensen (https://github.com/stigkj)
|
9
11
|
- Danny "northox" Fullerton (https://github.com/northox) negative time strings
|
data/README.rdoc
CHANGED
@@ -231,6 +231,46 @@ It can be handy for even more fine-grained control:
|
|
231
231
|
# non-critical
|
232
232
|
end
|
233
233
|
|
234
|
+
Please note that a mutex can also be used to prevent overlapping executions of the same job:
|
235
|
+
|
236
|
+
scheduler.every '5m', :mutex => 'the_mutex' do
|
237
|
+
puts "order ristretto"
|
238
|
+
# do something that might take more that 5 minutes...
|
239
|
+
puts "ah, that was delicious"
|
240
|
+
end
|
241
|
+
|
242
|
+
But beware the cascades...
|
243
|
+
|
244
|
+
|
245
|
+
== :mutex => ['mutex_a', 'mutex_b', ...]
|
246
|
+
|
247
|
+
Multiple mutexes can be used to ensure exlusivity:
|
248
|
+
|
249
|
+
scheduler.in '20m', :mutex => 'mutex_r' do
|
250
|
+
puts "order ristretto"
|
251
|
+
sleep 2 * 60
|
252
|
+
end
|
253
|
+
|
254
|
+
scheduler.in '20m' :mutex => 'mutex_e' do
|
255
|
+
puts "order espresso"
|
256
|
+
sleep 3 * 60
|
257
|
+
end
|
258
|
+
|
259
|
+
scheduler.in '1h' :mutex => ['mutex_r', 'mutex_e'] do
|
260
|
+
puts "code for fun"
|
261
|
+
end
|
262
|
+
|
263
|
+
This allow you order ristretto and espresso at same time, but when you coding it ensure you can't order any thing, and when you ordering anything it ensure you can't code.
|
264
|
+
|
265
|
+
Sure you can also use array of Mutex object directly:
|
266
|
+
|
267
|
+
mutex_r = Mutex.new
|
268
|
+
mutex_e = Mutex.new
|
269
|
+
# ...
|
270
|
+
scheduler.in '1h' :mutex => [mutex_r, mutex_e] do
|
271
|
+
puts "code for fun"
|
272
|
+
end
|
273
|
+
|
234
274
|
|
235
275
|
== :allow_overlapping => false
|
236
276
|
|
data/lib/rufus/sc/jobs.rb
CHANGED
@@ -365,11 +365,16 @@ module Scheduler
|
|
365
365
|
|
366
366
|
def determine_frequency
|
367
367
|
|
368
|
-
@frequency =
|
369
|
-
@t
|
370
|
-
|
371
|
-
|
372
|
-
|
368
|
+
@frequency =
|
369
|
+
if @t.is_a?(Fixnum) || @t.is_a?(Float)
|
370
|
+
@t
|
371
|
+
else
|
372
|
+
Rufus.parse_duration_string(@t)
|
373
|
+
end
|
374
|
+
|
375
|
+
raise ArgumentError.new(
|
376
|
+
'cannot initialize an EveryJob with a <= 0.0 frequency'
|
377
|
+
) if @frequency <= 0.0
|
373
378
|
end
|
374
379
|
|
375
380
|
def determine_at
|
data/lib/rufus/sc/rtime.rb
CHANGED
@@ -118,8 +118,13 @@ module Rufus
|
|
118
118
|
# Rufus.parse_time_string "1h10s" # => 3610.0
|
119
119
|
# Rufus.parse_time_string "1w2d" # => 777600.0
|
120
120
|
#
|
121
|
+
# Note will call #to_s on the input "string", so anything that is a String
|
122
|
+
# or responds to #to_s will be OK.
|
123
|
+
#
|
121
124
|
def self.parse_time_string(string)
|
122
125
|
|
126
|
+
string = string.to_s
|
127
|
+
|
123
128
|
return 0.0 if string == ''
|
124
129
|
|
125
130
|
m = string.match(/^(-?)([\d\.#{DURATION_LETTERS}]+)$/)
|
data/lib/rufus/sc/scheduler.rb
CHANGED
@@ -410,12 +410,25 @@ module Rufus::Scheduler
|
|
410
410
|
if params[:blocking]
|
411
411
|
block.call
|
412
412
|
elsif m = params[:mutex]
|
413
|
-
|
414
|
-
Thread.new { m.synchronize { block.call } }
|
413
|
+
Thread.new { synchronize_with_mutex(m, &block) }
|
415
414
|
else
|
416
415
|
Thread.new { block.call }
|
417
416
|
end
|
418
417
|
end
|
418
|
+
|
419
|
+
def synchronize_with_mutex(mutex, &block)
|
420
|
+
case mutex
|
421
|
+
when Mutex
|
422
|
+
mutex.synchronize { block.call }
|
423
|
+
when Array
|
424
|
+
mutex.reduce(block) do |memo, m|
|
425
|
+
m = (@mutexes[m.to_s] ||= Mutex.new) unless m.is_a?(Mutex)
|
426
|
+
lambda { m.synchronize { memo.call } }
|
427
|
+
end.call
|
428
|
+
else
|
429
|
+
(@mutexes[mutex.to_s] ||= Mutex.new).synchronize { block.call }
|
430
|
+
end
|
431
|
+
end
|
419
432
|
end
|
420
433
|
|
421
434
|
#--
|
@@ -549,8 +562,7 @@ module Rufus::Scheduler
|
|
549
562
|
if params[:blocking]
|
550
563
|
EM.next_tick { block.call }
|
551
564
|
elsif m = params[:mutex]
|
552
|
-
|
553
|
-
EM.defer { m.synchronize { block.call } }
|
565
|
+
EM.defer { synchronize_with_mutex(m, &block) }
|
554
566
|
else
|
555
567
|
EM.defer { block.call }
|
556
568
|
end
|
data/lib/rufus/sc/version.rb
CHANGED
data/out.txt
ADDED
data/spec/every_spec.rb
CHANGED
@@ -43,6 +43,51 @@ describe "#{SCHEDULER_CLASS}#every" do
|
|
43
43
|
var.should == 3
|
44
44
|
end
|
45
45
|
|
46
|
+
it 'schedules every 0.1s' do
|
47
|
+
|
48
|
+
var = 0
|
49
|
+
|
50
|
+
job = @s.every '0.1s' do
|
51
|
+
var += 1
|
52
|
+
end
|
53
|
+
|
54
|
+
sleep 3.7
|
55
|
+
|
56
|
+
var.should be_within(10).of(37)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises on schedule every 0s' do
|
60
|
+
|
61
|
+
lambda {
|
62
|
+
@s.every '0s' do
|
63
|
+
end
|
64
|
+
}.should raise_error(ArgumentError)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'raises on schedule every -1s' do
|
68
|
+
|
69
|
+
lambda {
|
70
|
+
@s.every '-1s' do
|
71
|
+
end
|
72
|
+
}.should raise_error(ArgumentError)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'raises on schedule every \'\'' do
|
76
|
+
|
77
|
+
lambda {
|
78
|
+
@s.every '' do
|
79
|
+
end
|
80
|
+
}.should raise_error(ArgumentError)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'raises on schedule every nil' do
|
84
|
+
|
85
|
+
lambda {
|
86
|
+
@s.every nil do
|
87
|
+
end
|
88
|
+
}.should raise_error(ArgumentError)
|
89
|
+
end
|
90
|
+
|
46
91
|
it 'is punctilious' do
|
47
92
|
|
48
93
|
hits = []
|
data/spec/job_spec.rb
CHANGED
data/spec/mutex_spec.rb
CHANGED
@@ -89,5 +89,71 @@ describe SCHEDULER_CLASS do
|
|
89
89
|
@s.instance_variable_get(:@mutexes).size.should == 0
|
90
90
|
end
|
91
91
|
end
|
92
|
+
|
93
|
+
context ':mutexes => Array of String' do
|
94
|
+
|
95
|
+
it 'ensure exclusivity' do
|
96
|
+
|
97
|
+
$var = ''
|
98
|
+
m0 = 'm0'
|
99
|
+
m1 = 'm1'
|
100
|
+
|
101
|
+
@s.in('1s', :mutex => m0) { MJOB.call(0) }
|
102
|
+
@s.in('1s', :mutex => m1) { MJOB.call(1) }
|
103
|
+
@s.in('1s', :mutex => [m0, m1]) { MJOB.call(2) }
|
104
|
+
|
105
|
+
sleep 4.5
|
106
|
+
|
107
|
+
$var.should include('in2out2')
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'creates new mutexes when the names are first encountered' do
|
111
|
+
|
112
|
+
@s.instance_variable_get(:@mutexes).size.should == 0
|
113
|
+
|
114
|
+
@s.in('1s', :mutex => ['fruit', 'bread']) { sleep 0.1 }
|
115
|
+
|
116
|
+
sleep 1.5
|
117
|
+
|
118
|
+
@s.instance_variable_get(:@mutexes).size.should == 2
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'creates a unique mutex for a given name' do
|
122
|
+
|
123
|
+
@s.in('1s', :mutex => ['fruit', 'bread']) { sleep 0.1 }
|
124
|
+
@s.in('1s', :mutex => ['fruit', 'bread']) { sleep 0.1 }
|
125
|
+
|
126
|
+
sleep 1.5
|
127
|
+
|
128
|
+
@s.instance_variable_get(:@mutexes).size.should == 2
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context ':mutexes => Array of Mutex' do
|
133
|
+
|
134
|
+
it 'ensure exclusivity' do
|
135
|
+
|
136
|
+
$var = ''
|
137
|
+
m0 = Mutex.new
|
138
|
+
m1 = Mutex.new
|
139
|
+
|
140
|
+
@s.in('1s', :mutex => m0) { MJOB.call(0) }
|
141
|
+
@s.in('1s', :mutex => m1) { MJOB.call(1) }
|
142
|
+
@s.in('1s', :mutex => [m0, m1]) { MJOB.call(2) }
|
143
|
+
|
144
|
+
sleep 4.5
|
145
|
+
|
146
|
+
$var.should include('in2out2')
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'does not register the mutexes' do
|
150
|
+
|
151
|
+
@s.in('1s', :mutex => [Mutex.new, Mutex.new]) { sleep 0.1 }
|
152
|
+
|
153
|
+
sleep 1.5
|
154
|
+
|
155
|
+
@s.instance_variable_get(:@mutexes).size.should == 0
|
156
|
+
end
|
157
|
+
end
|
92
158
|
end
|
93
159
|
|
data/spec/rtime_spec.rb
CHANGED
@@ -53,6 +53,23 @@ describe 'rufus/rtime' do
|
|
53
53
|
pts('5.m').should == 300.0
|
54
54
|
pts('1m.5s').should == 60.5
|
55
55
|
pts('-.5m').should == -30.0
|
56
|
+
|
57
|
+
pts('1d').should == 86400.0
|
58
|
+
pts('0.1d').should == 8640.0
|
59
|
+
pts('0.1s').should == 0.1
|
60
|
+
|
61
|
+
pts('0.1').should == 0.1
|
62
|
+
pts('1').should == 0.001
|
63
|
+
#
|
64
|
+
# the two evil twins :-(
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'parses duration "strings"' do
|
68
|
+
|
69
|
+
o = Object.new
|
70
|
+
def o.to_s; '-2'; end
|
71
|
+
|
72
|
+
pts(o).should == -0.002
|
56
73
|
end
|
57
74
|
|
58
75
|
it 'raises on wrong duration strings' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rufus-scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.19
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: tzinfo
|
@@ -67,38 +67,39 @@ extensions: []
|
|
67
67
|
extra_rdoc_files: []
|
68
68
|
files:
|
69
69
|
- Rakefile
|
70
|
-
- lib/rufus
|
71
|
-
- lib/rufus/scheduler.rb
|
72
|
-
- lib/rufus/sc/scheduler.rb
|
73
|
-
- lib/rufus/sc/rtime.rb
|
74
|
-
- lib/rufus/sc/version.rb
|
70
|
+
- lib/rufus/otime.rb
|
75
71
|
- lib/rufus/sc/cronline.rb
|
76
|
-
- lib/rufus/sc/jobs.rb
|
77
72
|
- lib/rufus/sc/jobqueues.rb
|
78
|
-
- lib/rufus/
|
79
|
-
-
|
80
|
-
-
|
81
|
-
-
|
82
|
-
-
|
83
|
-
-
|
84
|
-
- spec/timeout_spec.rb
|
85
|
-
- spec/at_spec.rb
|
73
|
+
- lib/rufus/sc/jobs.rb
|
74
|
+
- lib/rufus/sc/rtime.rb
|
75
|
+
- lib/rufus/sc/scheduler.rb
|
76
|
+
- lib/rufus/sc/version.rb
|
77
|
+
- lib/rufus/scheduler.rb
|
78
|
+
- lib/rufus-scheduler.rb
|
86
79
|
- spec/at_in_spec.rb
|
87
|
-
- spec/
|
80
|
+
- spec/at_spec.rb
|
81
|
+
- spec/blocking_spec.rb
|
82
|
+
- spec/cron_spec.rb
|
88
83
|
- spec/cronline_spec.rb
|
89
|
-
- spec/
|
84
|
+
- spec/every_spec.rb
|
85
|
+
- spec/exception_spec.rb
|
86
|
+
- spec/in_spec.rb
|
87
|
+
- spec/job_spec.rb
|
90
88
|
- spec/mutex_spec.rb
|
89
|
+
- spec/rtime_spec.rb
|
90
|
+
- spec/schedulable_spec.rb
|
91
91
|
- spec/scheduler_spec.rb
|
92
|
-
- spec/
|
93
|
-
- spec/
|
94
|
-
- spec/
|
95
|
-
- test/t.rb
|
92
|
+
- spec/spec_base.rb
|
93
|
+
- spec/stress_schedule_unschedule_spec.rb
|
94
|
+
- spec/timeout_spec.rb
|
96
95
|
- test/kjw.rb
|
96
|
+
- test/t.rb
|
97
97
|
- rufus-scheduler.gemspec
|
98
98
|
- CHANGELOG.txt
|
99
|
-
- TODO.txt
|
100
|
-
- LICENSE.txt
|
101
99
|
- CREDITS.txt
|
100
|
+
- LICENSE.txt
|
101
|
+
- out.txt
|
102
|
+
- TODO.txt
|
102
103
|
- README.rdoc
|
103
104
|
homepage: http://github.com/jmettraux/rufus-scheduler
|
104
105
|
licenses: []
|
@@ -114,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
115
|
version: '0'
|
115
116
|
segments:
|
116
117
|
- 0
|
117
|
-
hash:
|
118
|
+
hash: -1513262691769122142
|
118
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
120
|
none: false
|
120
121
|
requirements:
|
@@ -123,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
124
|
version: '0'
|
124
125
|
segments:
|
125
126
|
- 0
|
126
|
-
hash:
|
127
|
+
hash: -1513262691769122142
|
127
128
|
requirements: []
|
128
129
|
rubyforge_project: rufus
|
129
130
|
rubygems_version: 1.8.24
|