asir 1.2.8 → 1.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +7 -0
- data/lib/asir/adaptive_value.rb +81 -0
- data/lib/asir/error.rb +3 -3
- data/lib/asir/main.rb +1 -1
- data/lib/asir/message.rb +1 -1
- data/lib/asir/retry_behavior.rb +20 -12
- data/lib/asir/transport.rb +1 -1
- data/lib/asir/version.rb +1 -1
- data/spec/adaptive_value_spec.rb +103 -0
- data/spec/message_spec.rb +1 -1
- data/spec/retry_behavior_spec.rb +56 -0
- metadata +9 -4
data/ChangeLog
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
2012-06-19 Kurt A. Stephens <ks.github@kurtstephens.com>
|
2
|
+
|
3
|
+
* v1.2.9: New Version: Fixes, New Functionality.
|
4
|
+
* ASIR::Error::Unforwardable.unforwardable is deprecated; use .modules.
|
5
|
+
* ASIR::AdaptiveValue: refactor ASIR::RetryBehavior sleep values.
|
6
|
+
* BUG: Transport#after_receive_message.call takes a Message::State.
|
7
|
+
|
1
8
|
2012-03-14 Kurt A. Stephens <ks.github@kurtstephens.com>
|
2
9
|
|
3
10
|
* v1.2.8: New Version: Additional functionality.
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module ASIR
|
2
|
+
# Adaptive Value.
|
3
|
+
# Return a Numeric #value which adapts.
|
4
|
+
# Useful for controlling adaptive retry sleep amounts or other
|
5
|
+
# values that must be stochastic.
|
6
|
+
#
|
7
|
+
# #init must be specified.
|
8
|
+
# #rand_factor should be a Float.
|
9
|
+
#
|
10
|
+
class AdaptiveValue
|
11
|
+
attr_accessor :init, :min, :max, :add, :mult, :rand_factor
|
12
|
+
|
13
|
+
def initialize opts = nil
|
14
|
+
if opts
|
15
|
+
opts.each do | k, v |
|
16
|
+
send(:"#{k}=", v)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a new value limited by #min and #max after applying the addition of #rand_factor.
|
22
|
+
def value
|
23
|
+
v = @value || init_or_error
|
24
|
+
v += v * rand(@rand_factor) if @rand_factor
|
25
|
+
v = @min if @min && v < @min
|
26
|
+
v = @max if @max && v > @max
|
27
|
+
v
|
28
|
+
end
|
29
|
+
def value= x
|
30
|
+
@value = x
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns a cached #value until #reset! or #new_value!.
|
34
|
+
def value!
|
35
|
+
@value_ ||= value
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns a new cached #value.
|
39
|
+
def new_value!
|
40
|
+
@value_ = nil
|
41
|
+
value!
|
42
|
+
end
|
43
|
+
|
44
|
+
# Resets #value to #init.
|
45
|
+
def reset!
|
46
|
+
@value_ = @value = nil
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_i
|
51
|
+
x = value.to_i
|
52
|
+
adapt!
|
53
|
+
x
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_f
|
57
|
+
x = value.to_f
|
58
|
+
adapt!
|
59
|
+
x
|
60
|
+
end
|
61
|
+
|
62
|
+
# Increments value by #add, if #add is set.
|
63
|
+
# Multiplies value by #mult, if #mult is set.
|
64
|
+
# Limits value by #min and #max.
|
65
|
+
def adapt!
|
66
|
+
@value ||= init_or_error
|
67
|
+
@value += @add if @add
|
68
|
+
@value *= @mult if @mult
|
69
|
+
@value = @min if @min && @value < @min
|
70
|
+
@value = @max if @max && @value > @max
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def init_or_error
|
76
|
+
@init or raise ArgumentError, "init: not set"
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/lib/asir/error.rb
CHANGED
@@ -39,9 +39,9 @@ module ASIR
|
|
39
39
|
super(msg)
|
40
40
|
self.set_backtrace original && original.backtrace
|
41
41
|
end
|
42
|
-
def self.
|
43
|
-
def self.
|
44
|
-
@@
|
42
|
+
def self.modules; @@modules; end
|
43
|
+
def self.modules= x; @@modules = x; end
|
44
|
+
@@modules ||= [
|
45
45
|
::SystemExit,
|
46
46
|
::SystemStackError,
|
47
47
|
::NoMemoryError,
|
data/lib/asir/main.rb
CHANGED
@@ -377,7 +377,7 @@ END
|
|
377
377
|
transport.after_receive_message = lambda do | transport, state |
|
378
378
|
message = state.message
|
379
379
|
$0 = "#{old_arg0} #{transport.message_count} #{message.identifier}"
|
380
|
-
after_receive_message.call(transport,
|
380
|
+
after_receive_message.call(transport, state)
|
381
381
|
end
|
382
382
|
transport.run_server!
|
383
383
|
self
|
data/lib/asir/message.rb
CHANGED
@@ -18,7 +18,7 @@ module ASIR
|
|
18
18
|
|
19
19
|
def invoke!
|
20
20
|
@result = Result.new(self, @receiver.__send__(@selector, *@arguments))
|
21
|
-
rescue *Error::Unforwardable.
|
21
|
+
rescue *Error::Unforwardable.modules => exc
|
22
22
|
@result = Result.new(self, nil, Error::Unforwardable.new(exc))
|
23
23
|
rescue ::Exception => exc
|
24
24
|
@result = Result.new(self, nil, exc)
|
data/lib/asir/retry_behavior.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'asir/error'
|
2
|
+
require 'asir/adaptive_value'
|
3
|
+
|
1
4
|
module ASIR
|
2
5
|
# !SLIDE
|
3
6
|
# Generic retry behavior
|
@@ -12,13 +15,15 @@ module ASIR
|
|
12
15
|
attr_accessor :try_sleep_max
|
13
16
|
|
14
17
|
# Yields:
|
15
|
-
# :try, n_try
|
16
|
-
# :rescue, exc
|
17
|
-
# :retry, exc
|
18
|
-
# :failed,
|
18
|
+
# :try, n_try - for each attempt.
|
19
|
+
# :rescue, exc - for any rescued exception.
|
20
|
+
# :retry, exc - before each retry.
|
21
|
+
# :failed, last_exc - when too many retrys occurred.
|
19
22
|
def with_retry
|
20
23
|
n_try = 0
|
21
|
-
|
24
|
+
@try_sleep_value ||= ::ASIR::AdaptiveValue.new
|
25
|
+
@try_sleep_value.init = try_sleep
|
26
|
+
@try_sleep_value.reset!
|
22
27
|
result = done = last_exception = nil
|
23
28
|
begin
|
24
29
|
n_try += 1
|
@@ -26,24 +31,27 @@ module ASIR
|
|
26
31
|
done = true
|
27
32
|
rescue *Error::Unrecoverable.modules
|
28
33
|
raise
|
29
|
-
rescue *Error::Unforwardable.
|
34
|
+
rescue *Error::Unforwardable.modules
|
30
35
|
raise
|
31
36
|
rescue ::Exception => exc
|
32
|
-
|
37
|
+
last_exc = exc
|
33
38
|
yield :rescue, exc
|
34
39
|
if ! try_max || try_max > n_try
|
35
40
|
yield :retry, exc
|
36
|
-
if
|
41
|
+
if try_sleep
|
42
|
+
sleep_secs = @try_sleep_value.value
|
37
43
|
sleep sleep_secs if sleep_secs > 0
|
38
|
-
|
39
|
-
|
44
|
+
@try_sleep_value.init = try_sleep
|
45
|
+
@try_sleep_value.add = try_sleep_increment
|
46
|
+
@try_sleep_value.max = try_sleep_max
|
47
|
+
@try_sleep_value.adapt!
|
40
48
|
end
|
41
49
|
retry
|
42
50
|
end
|
43
51
|
end
|
44
52
|
unless done
|
45
|
-
unless yield :failed,
|
46
|
-
exc =
|
53
|
+
unless yield :failed, last_exc
|
54
|
+
exc = last_exc
|
47
55
|
raise RetryError, "Retry failed: #{exc.inspect}", exc.backtrace
|
48
56
|
end
|
49
57
|
end
|
data/lib/asir/transport.rb
CHANGED
@@ -165,7 +165,7 @@ module ASIR
|
|
165
165
|
if message_ok
|
166
166
|
if exception && ! result_ok
|
167
167
|
case exception
|
168
|
-
when *Error::Unforwardable.
|
168
|
+
when *Error::Unforwardable.modules
|
169
169
|
unforwardable_exception = exception = Error::Unforwardable.new(exception)
|
170
170
|
end
|
171
171
|
state.result = Result.new(state.message, nil, exception)
|
data/lib/asir/version.rb
CHANGED
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'asir/adaptive_value'
|
2
|
+
|
3
|
+
describe ASIR::AdaptiveValue do
|
4
|
+
it "should have a #value of #init." do
|
5
|
+
av = ASIR::AdaptiveValue.new(:init => 5)
|
6
|
+
av.value.should == 5
|
7
|
+
av.value.should == 5
|
8
|
+
av.value!.should == 5
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have a #value limited by #min." do
|
12
|
+
av = ASIR::AdaptiveValue.new(:init => 5, :min => 10)
|
13
|
+
av.value.should == 10
|
14
|
+
av.value.should == 10
|
15
|
+
av.value!.should == 10
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should have a #value not limited by #min." do
|
19
|
+
av = ASIR::AdaptiveValue.new(:init => 15, :min => 10)
|
20
|
+
av.value.should == 15
|
21
|
+
av.value.should == 15
|
22
|
+
av.value!.should == 15
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should have a #value limited by #max." do
|
26
|
+
av = ASIR::AdaptiveValue.new(:init => 5, :max => 10)
|
27
|
+
av.value.should == 5
|
28
|
+
av.value.should == 5
|
29
|
+
av.value!.should == 5
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have a #value not limited by #max." do
|
33
|
+
av = ASIR::AdaptiveValue.new(:init => 15, :max => 10)
|
34
|
+
av.value.should == 10
|
35
|
+
av.value.should == 10
|
36
|
+
av.value!.should == 10
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have a #value adjusted by #add." do
|
40
|
+
av = ASIR::AdaptiveValue.new(:init => 1, :add => 2)
|
41
|
+
av.value.should == 1
|
42
|
+
av.value.should == 1
|
43
|
+
av.adapt!
|
44
|
+
av.value.should == 3
|
45
|
+
av.value.should == 3
|
46
|
+
av.value!.should == 3
|
47
|
+
av.adapt!
|
48
|
+
av.value.should == 5
|
49
|
+
av.value.should == 5
|
50
|
+
av.value!.should == 3
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should have a #value adjusted by #mult." do
|
54
|
+
av = ASIR::AdaptiveValue.new(:init => 10, :mult => 1.2)
|
55
|
+
av.value.should == 10
|
56
|
+
av.value.should == 10
|
57
|
+
av.adapt!
|
58
|
+
av.value.to_i.should == 12
|
59
|
+
av.value.to_i.should == 12
|
60
|
+
av.value!.to_i.should == 12
|
61
|
+
av.adapt!
|
62
|
+
av.value.to_i.should == 14
|
63
|
+
av.value.to_i.should == 14
|
64
|
+
av.value!.to_i.should == 12
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should have an adapting #to_i and #to_f value." do
|
68
|
+
av = ASIR::AdaptiveValue.new(:init => 10, :mult => 1.2)
|
69
|
+
av.to_i.should == 10
|
70
|
+
av.to_f.should be_within(0.1).of(12.0)
|
71
|
+
av.to_f.should be_within(0.1).of(14.4)
|
72
|
+
av.to_f.should be_within(0.01).of(17.28)
|
73
|
+
av.to_i.should == 20
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should have a #value adjusted by #rand_factor." do
|
77
|
+
av = ASIR::AdaptiveValue.new(:init => 10, :rand_factor => 0.5)
|
78
|
+
def av._ri
|
79
|
+
@_ri ||= -1
|
80
|
+
@_ri += 1
|
81
|
+
end
|
82
|
+
def av._rv
|
83
|
+
@_rv ||= (0...10).to_a
|
84
|
+
end
|
85
|
+
def av.rand scale
|
86
|
+
(_rv[_ri % _rv.size] / 10.0) * scale
|
87
|
+
end
|
88
|
+
|
89
|
+
av.value.should == 10
|
90
|
+
av.value.should == 10.5
|
91
|
+
av.value!.should == 11.0
|
92
|
+
av.value.should == 11.5
|
93
|
+
av.value.should == 12.0
|
94
|
+
av.value!.should == 11.0
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should raise error if #init is not set." do
|
98
|
+
av = ASIR::AdaptiveValue.new(:rand_factor => 0.5)
|
99
|
+
lambda do
|
100
|
+
av.value
|
101
|
+
end.should raise_error(ArgumentError, /init: not set/)
|
102
|
+
end
|
103
|
+
end
|
data/spec/message_spec.rb
CHANGED
@@ -47,7 +47,7 @@ describe "ASIR::Message" do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'should capture Unforwardable exceptions.' do
|
50
|
-
cls = ::ASIR::Error::Unforwardable.
|
50
|
+
cls = ::ASIR::Error::Unforwardable.modules.first
|
51
51
|
cls.should_not == nil
|
52
52
|
msg = "This message".freeze
|
53
53
|
message.selector = :raise_exception!
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'asir/retry_behavior'
|
2
|
+
|
3
|
+
describe ASIR::RetryBehavior do
|
4
|
+
let(:cls) do
|
5
|
+
Class.new do
|
6
|
+
include ASIR::RetryBehavior
|
7
|
+
attr_accessor :sleeps
|
8
|
+
def sleeps; @sleeps ||= [ ]; end
|
9
|
+
def sleep x; sleeps << x; end
|
10
|
+
def yields; @yields ||= [ ]; end
|
11
|
+
def yielder &blk
|
12
|
+
Proc.new do | kind, value |
|
13
|
+
yields << [ kind, value ]
|
14
|
+
blk.call kind, value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
subject { cls.new }
|
20
|
+
|
21
|
+
it 'should retry only try_max times, then raise RetryError' do
|
22
|
+
blk = subject.yielder do | kind, value |
|
23
|
+
raise "Fail" if kind == :try
|
24
|
+
end
|
25
|
+
subject.try_max = 10
|
26
|
+
lambda do
|
27
|
+
subject.with_retry(&blk)
|
28
|
+
end.should raise_error(ASIR::RetryBehavior::RetryError)
|
29
|
+
subject.sleeps.should == [ ]
|
30
|
+
subject.yields.select{|x| x[0] == :try}.map{|x| x[1]}.should == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
31
|
+
subject.yields.select{|x| x[0] == :rescue}.map{|x| x[1]}.size.should == 10
|
32
|
+
subject.yields.select{|x| x[0] == :retry}.map{|x| x[1]}.size.should == 9
|
33
|
+
subject.yields.select{|x| x[0] == :failed}.map{|x| x[1]}.size.should == 1
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should sleep for increasing amounts' do
|
37
|
+
blk = subject.yielder do | kind, value |
|
38
|
+
raise "Fail" if kind == :try
|
39
|
+
end
|
40
|
+
subject.try_max = 10
|
41
|
+
subject.try_sleep = 10
|
42
|
+
subject.try_sleep_increment = 2
|
43
|
+
lambda do
|
44
|
+
subject.with_retry(&blk)
|
45
|
+
end.should raise_error(ASIR::RetryBehavior::RetryError)
|
46
|
+
subject.sleeps.should == [10, 12, 14, 16, 18, 20, 22, 24, 26]
|
47
|
+
|
48
|
+
subject.sleeps.clear
|
49
|
+
subject.yields.clear
|
50
|
+
lambda do
|
51
|
+
subject.with_retry(&blk)
|
52
|
+
end.should raise_error(ASIR::RetryBehavior::RetryError)
|
53
|
+
subject.sleeps.should == [10, 12, 14, 16, 18, 20, 22, 24, 26]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asir
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.9
|
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-06-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: uuid
|
@@ -178,6 +178,7 @@ files:
|
|
178
178
|
- lab/phony_proc.rb
|
179
179
|
- lab/spoon_test.rb
|
180
180
|
- lib/asir.rb
|
181
|
+
- lib/asir/adaptive_value.rb
|
181
182
|
- lib/asir/additional_data.rb
|
182
183
|
- lib/asir/application.rb
|
183
184
|
- lib/asir/channel.rb
|
@@ -242,12 +243,14 @@ files:
|
|
242
243
|
- lib/asir/uri_config.rb
|
243
244
|
- lib/asir/uuid.rb
|
244
245
|
- lib/asir/version.rb
|
246
|
+
- spec/adaptive_value_spec.rb
|
245
247
|
- spec/client_spec.rb
|
246
248
|
- spec/debug_helper.rb
|
247
249
|
- spec/demux_spec.rb
|
248
250
|
- spec/example_spec.rb
|
249
251
|
- spec/message_spec.rb
|
250
252
|
- spec/performance_spec.rb
|
253
|
+
- spec/retry_behavior_spec.rb
|
251
254
|
- spec/spec_helper.rb
|
252
255
|
- spec/thread_pool_spec.rb
|
253
256
|
- spec/thread_variable_spec.rb
|
@@ -270,7 +273,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
270
273
|
version: '0'
|
271
274
|
segments:
|
272
275
|
- 0
|
273
|
-
hash:
|
276
|
+
hash: -2116348420781161108
|
274
277
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
275
278
|
none: false
|
276
279
|
requirements:
|
@@ -279,7 +282,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
279
282
|
version: '0'
|
280
283
|
segments:
|
281
284
|
- 0
|
282
|
-
hash:
|
285
|
+
hash: -2116348420781161108
|
283
286
|
requirements: []
|
284
287
|
rubyforge_project:
|
285
288
|
rubygems_version: 1.8.25
|
@@ -287,12 +290,14 @@ signing_key:
|
|
287
290
|
specification_version: 3
|
288
291
|
summary: Abstracting Services in Ruby
|
289
292
|
test_files:
|
293
|
+
- spec/adaptive_value_spec.rb
|
290
294
|
- spec/client_spec.rb
|
291
295
|
- spec/debug_helper.rb
|
292
296
|
- spec/demux_spec.rb
|
293
297
|
- spec/example_spec.rb
|
294
298
|
- spec/message_spec.rb
|
295
299
|
- spec/performance_spec.rb
|
300
|
+
- spec/retry_behavior_spec.rb
|
296
301
|
- spec/spec_helper.rb
|
297
302
|
- spec/thread_pool_spec.rb
|
298
303
|
- spec/thread_variable_spec.rb
|