asir 1.2.8 → 1.2.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.
- 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
|