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 CHANGED
@@ -2,7 +2,13 @@
2
2
  = rufus-scheduler CHANGELOG.txt
3
3
 
4
4
 
5
- == rufus-scheduler - 2.0.18 released 2012/03/06
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 = if @t.is_a?(Fixnum) || @t.is_a?(Float)
369
- @t
370
- else
371
- Rufus.parse_duration_string(@t)
372
- end
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
@@ -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}]+)$/)
@@ -410,12 +410,25 @@ module Rufus::Scheduler
410
410
  if params[:blocking]
411
411
  block.call
412
412
  elsif m = params[:mutex]
413
- m = (@mutexes[m.to_s] ||= Mutex.new) unless m.is_a?(Mutex)
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
- m = (@mutexes[m.to_s] ||= Mutex.new) unless m.is_a?(Mutex)
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
@@ -26,7 +26,7 @@
26
26
  module Rufus
27
27
  module Scheduler
28
28
 
29
- VERSION = '2.0.18'
29
+ VERSION = '2.0.19'
30
30
  end
31
31
  end
32
32
 
data/out.txt ADDED
@@ -0,0 +1,4 @@
1
+ ruby-1.8.7-p249 :001 > nada
2
+ NameError: undefined local variable or method `nada' for #<Object:0x1001d1298>
3
+ from (irb):1
4
+ ruby-1.8.7-p249 :002 > ^D
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
@@ -40,7 +40,7 @@ describe 'job classes' do
40
40
  job.running.should == true
41
41
  end
42
42
 
43
- it 'returns false when the job hit some error' do
43
+ it 'returns false when the job hits some error' do
44
44
 
45
45
  $exception = nil
46
46
 
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.18
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-03-05 00:00:00.000000000 Z
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-scheduler.rb
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/otime.rb
79
- - spec/job_spec.rb
80
- - spec/stress_schedule_unschedule_spec.rb
81
- - spec/schedulable_spec.rb
82
- - spec/exception_spec.rb
83
- - spec/in_spec.rb
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/spec_base.rb
80
+ - spec/at_spec.rb
81
+ - spec/blocking_spec.rb
82
+ - spec/cron_spec.rb
88
83
  - spec/cronline_spec.rb
89
- - spec/rtime_spec.rb
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/blocking_spec.rb
93
- - spec/every_spec.rb
94
- - spec/cron_spec.rb
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: 4543164608551708958
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: 4543164608551708958
127
+ hash: -1513262691769122142
127
128
  requirements: []
128
129
  rubyforge_project: rufus
129
130
  rubygems_version: 1.8.24