rhod 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 99aa65709753429dc68b3979f9397bf2502e13ad
4
- data.tar.gz: cd2856de21b568e00fa7bb7b097125ff722704b5
3
+ metadata.gz: f1d610e43d6cd0ea21bc4bf99bd68e4728f26cbd
4
+ data.tar.gz: ea6aba49b9e5df02cedf9988f6ba8915df2e1f99
5
5
  SHA512:
6
- metadata.gz: 2245e308b5b535497b54e24681d7f512ca906b3dd1936897568b2022715063b66ed972ccb33cf0f68efdd81df5ec970533f0e67845aa01cbebd4e11762de4217
7
- data.tar.gz: f8b786cde49e380879e0339513d9470f8a9c222e62e3f21eea915a3f821931b43e1b4a22752f64a9fdc8d4de8c76483b961f5fcc6a5326f58bf12f8480301df4
6
+ metadata.gz: 0b30aebc6f171b35d4dc581824d7e0a1466d308e4cc1f4927c5d791d3382ef3b75880cb7e1fa7a122daafd4df45b96c5d978d3ea2e6f377cd933c8cbd6142dc5
7
+ data.tar.gz: 2997412a10c2d10e3a3a2f2eca8df58387459f95fbe6a5da15f6473cb07383bdc5bc6c21ad62d83e0572154144cac0d324f0e0322843ac11ec09b0fc7f3573aa
@@ -0,0 +1,8 @@
1
+ # v0.0.3
2
+ Add support for connection pooling to be attached to a Rhod command.
3
+
4
+ # v0.0.2
5
+ Added syntax sugar around backoff definitions.
6
+
7
+ # v0.0.1
8
+ First Public Release.
data/README.md CHANGED
@@ -12,214 +12,107 @@ A Lightweight High Avalibility framework for Ruby, inspired by [Hystrix](https:/
12
12
 
13
13
  Rhod helps you handle failures gracefully, even during a firefight. When your code has to interact with other services, it also means writing code to keep it running in the event of failure. Failures can include exceptions, timeouts, downed hosts, and any number of issues that are caused by events outside of your application.
14
14
 
15
- Rhod allows you to fully customize how your application reacts when it can't reach a service it needs. but by default it is configured for a 'fail fast' scenario. With some configuration, Rhod can support the following failure scenarios and variations on them:
16
-
17
- - Fail Fast
18
- - Retry N times before Fail
19
- - Retry N times with progressive backoffs before Fail
20
- - Fail Silent
21
- - Fail w/ Fallback
22
- - Primary / Secondary ("hot spare") switch over
23
-
24
- ## Installation
25
-
26
- Rhod requires Ruby 1.9.2 or greater.
27
-
28
- Add this line to your application's Gemfile:
29
-
30
- ```ruby
31
- gem 'rhod'
32
- ```
15
+ # Is it any good?
33
16
 
34
- And then execute:
35
-
36
- $ bundle
37
-
38
- Or install it yourself as:
39
-
40
- $ gem install rhod
41
-
42
- ## Configuration
43
-
44
- To configure Rhod's defaults, change any of the keys in `Rhod.defaults`
45
-
46
- ```ruby
47
- Rhod.defaults
48
- => {:retries=>0,
49
- :backoffs=>#<Enumerator: ...>,
50
- :fallback=>nil}
51
- ```
17
+ [Yes](https://news.ycombinator.com/item?id=3067434)
52
18
 
53
19
  ## Usage
54
20
 
55
21
  Rhod has a very simple API. Design your application as you would normally, then enclose network accessing portions of your code with:
56
22
 
57
23
  ```ruby
58
- Rhod.execute do
24
+ Rhod.with_default do
59
25
  ...
60
26
  end
61
27
  ```
62
28
 
63
- This implements the "Fail Fast" scenario by default.
64
-
65
- Example, open a remote reasource, fail immediately if it fails:
66
-
67
- ```ruby
68
- require 'open-uri'
69
- require 'rhod'
70
-
71
- Rhod.execute { open("http://google.com").read }
72
- ```
73
-
74
- ## An Important note about arguments:
75
-
76
- Do not reach into the outer scope when using Rhod, instead you can pass arguments into your block like so:
77
-
78
- ```ruby
79
- address = "http://google.com"
80
-
81
- Rhod.execute(address) do |url|
82
- open(url).read
83
- end
84
- ```
85
-
86
- If you need to pass options to Rhod, pass them as the last argument:
87
-
88
- ```ruby
89
- # Works the same as the above, with but with retires.
90
- address = "http://google.com"
91
-
92
- Rhod.execute(address, :retries => 5) do |url|
93
- open(url).read
94
- end
95
- ```
96
-
97
- ### Retries with and without backoffs
29
+ This implements the [Fail Fast](https://github.com/dinedal/rhod/wiki/Fail-Fast) scenario by default.
98
30
 
99
- #### Idempotence Caution
100
-
101
- Code within a `Rhod::Command` block with reties in use must be _idempotent_, i.e., safe to run multiple times.
31
+ Rhod allows you to fully customize how your application reacts when it can't reach a service it needs. but by default it is configured for a 'fail fast' scenario. With some configuration, Rhod can support the following failure scenarios and variations on them:
102
32
 
103
- Rhod supports retying up to N times. By default it uses a logarithmic backoff:
33
+ - [Fail Fast](https://github.com/dinedal/rhod/wiki/Fail-Fast)
34
+ - [Retry N times before Fail](https://github.com/dinedal/rhod/wiki/Retry-N-times-before-Fail)
35
+ - [Retry N times with progressive backoffs before Fail](Retry-N-times-with-progressive-backoffs-before-Fail)
36
+ - [Fail Silent](https://github.com/dinedal/rhod/wiki/Fail-Silent)
37
+ - [Fail w/ Fallback](https://github.com/dinedal/rhod/wiki/Fail-with-Fallback)
38
+ - [Primary / Secondary ("hot spare") switch over](https://github.com/dinedal/rhod/wiki/Primary-Secondary-Switchover)
104
39
 
105
- ```ruby
106
- Rhod::Backoffs.default.take(5)
107
- # [0.7570232465074598, 2.403267722339301, 3.444932048942182, 4.208673319629471, 4.811984719351674]
108
- ```
40
+ Check the [wiki](https://github.com/dinedal/rhod/wiki/) for more documentation.
109
41
 
110
- Rhod also comes with exponential and constant (always the same value) backoffs. You can also supply any Enumerator that produces a series of numbers. See `lib/rhod/backoffs.rb` for examples.
42
+ ## Upgrading from v0.0.x to v0.1.x
111
43
 
112
- Example, open a remote reasource, fail once it has failed 10 times, with the default (logarithmic) backoff:
44
+ The only breaking API change is that backoffs have changed in their creation, dropping `Enumerator` in favor of a simple threadsafe class. Please switch any custom backoff code subclass `Rhod::Backoffs::Backoff`.
113
45
 
114
- ```ruby
115
- require 'open-uri'
116
- require 'rhod'
46
+ ## Installation
117
47
 
118
- Rhod::Command.execute(:retries => 10) { open("http://google.com").read }
119
- ```
48
+ Rhod requires Ruby 1.9.2 or greater.
120
49
 
121
- Example, open a remote reasource, fail once it has failed 10 times, waiting 0.2 seconds between attempts:
50
+ Add this line to your application's Gemfile:
122
51
 
123
52
  ```ruby
124
- require 'open-uri'
125
- require 'rhod'
126
-
127
- Rhod.execute(:retries => 10, :backoffs => 0.2) do
128
- open("http://google.com").read
129
- end
53
+ gem 'rhod'
130
54
  ```
131
55
 
132
- Example, open a remote reasource, fail once it has failed 10 times, with an exponetially growing wait time between attempts:
133
-
134
- ```ruby
135
- require 'open-uri'
136
- require 'rhod'
56
+ And then execute:
137
57
 
138
- Rhod.execute(:retries => 10, :backoffs => :^) do
139
- open("http://google.com").read
140
- end
141
- ```
58
+ $ bundle
142
59
 
143
- Example, open a remote reasource, fail once it has failed 10 times, with no waiting between attempts:
60
+ Or install it yourself as:
144
61
 
145
- ```ruby
146
- require 'open-uri'
147
- require 'rhod'
62
+ $ gem install rhod
148
63
 
149
- Rhod.execute(:retries => 10, :backoffs => 0) do
150
- open("http://google.com").read
151
- end
152
- ```
64
+ ## Configuration
153
65
 
154
- Example, open a remote reasource, fail once it has failed 10 times, with a random wait between 1 and 5 seconds on each attempt
66
+ To configure Rhod's defaults, just overwrite the default profile with any changes you'd like to make.
155
67
 
156
68
  ```ruby
157
- require 'open-uri'
158
- require 'rhod'
159
-
160
- Rhod.execute(:retries => 10, :backoffs => 'r1..5') do
161
- open("http://google.com").read
162
- end
69
+ Rhod.create_profile(:default, retries: 10)
70
+ # => {:retries=>10,
71
+ # :backoffs=>#<Rhod::Backoffs::Logarithmic:0x007f89afaeb4c0 @state=1.3>,
72
+ # :fallback=>nil,
73
+ # :pool=>
74
+ # #<ConnectionPool:0x007f89afaeb470
75
+ # @available=
76
+ # #<ConnectionPool::TimedStack:0x007f89afaeb3d0
77
+ # @mutex=#<Mutex:0x007f89afaeb358>,
78
+ # @que=[nil],
79
+ # @resource=
80
+ # #<ConditionVariable:0x007f89afaeb330
81
+ # @waiters={},
82
+ # @waiters_mutex=#<Mutex:0x007f89afaeb2e0>>>,
83
+ # @key=:"current-70114667354600",
84
+ # @size=1,
85
+ # @timeout=0>,
86
+ # :exceptions=>[Exception, StandardError]}
163
87
  ```
164
88
 
165
-
166
- ### Fail Silent
167
-
168
- In the event of a failure, Rhod falls back to a `fallback`. The most basic case is to fall back to a constant value.
169
-
170
- Example, open a remote reasource, if it fails return them empty string.
89
+ Creating a new profile will copy from the default profile any unspecified options:
171
90
 
172
91
  ```ruby
173
- require 'open-uri'
174
- require 'rhod'
92
+ Rhod.create_profile(:redis,
93
+ retries: 10,
94
+ backoffs: :^,
95
+ pool: ConnectionPool.new(size: 3, timeout: 10) { Redis.new },
96
+ exceptions: [Redis::BaseError])
175
97
 
176
- Rhod.execute(:fallback => -> {""}) do
177
- open("http://google.com").read
178
- end
98
+ Rhod.with_redis("1") {|r, a| r.set('test',a)}
99
+ # => "OK"
100
+ Rhod.with_redis {|r| r.get('test')}
101
+ # => "1"
179
102
  ```
180
103
 
181
- ### Fail w/ Fallback
182
-
183
- If there is another network call that can be used to fetch the reasource, it's possible to use another `Rhod::Command` once a failure has occurred.
184
-
185
- ```ruby
186
- require 'open-uri'
187
- require 'rhod'
104
+ ## Idempotence Caution
188
105
 
189
- search_engine_fallback = Rhod::Command.new(
190
- :fallback => -> {""} # couldn't get anything
191
- ) do
192
- open("https://yahoo.com").read
193
- end
106
+ Code within a `Rhod::Command` block with reties in use must be _idempotent_, i.e., safe to run multiple times.
194
107
 
195
- Rhod.execute(:fallback => -> { search_engine_fallback.execute }) do
196
- open("http://google.com").read
197
- end
198
- ```
108
+ ## Passing arguments
199
109
 
200
- ### Primary / Secondary ("Hot Spare") switch over
110
+ Code within a `Rhod::Command` should avoid leaking memory and/or scope by having arguments passed to it:
201
111
 
202
- Sometimes the fallback is just a part of normal operation. Just code in the state of which back end to access.
112
+ ### Good use of argument passing:
203
113
 
204
114
  ```ruby
205
- require 'open-uri'
206
- require 'rhod'
207
-
208
- class SearchEngineHTML
209
- attr_accessor :secondary
210
-
211
- def fetch
212
- url = !@secondary ? "http://google.com" : "https://yahoo.com"
213
-
214
- Rhod.execute(url, :fallback => Proc.new { @secondary = !@secondary; fetch }) do |url|
215
- open(url).read
216
- end
217
- end
218
- end
219
-
220
- search_engine_html = SearchEngineHTML.new
221
-
222
- search_engine_html.fetch
115
+ Rhod.with_default("http://google.com") {|url| open(url).read}
223
116
  ```
224
117
 
225
118
  ## Connection Pools
@@ -231,9 +124,12 @@ require 'rhod'
231
124
  require 'redis'
232
125
  require 'connection_pool'
233
126
 
234
- Rhod.connection_pools[:redis] = ConnectionPool.new(size:3, timeout:5) { Redis.new }
127
+ Rhod.create_profile(:redis,
128
+ pool: ConnectionPool.new(size: 3, timeout: 5) { Redis.new }
129
+ )
235
130
 
236
- Rhod.execute(:pool => :redis) {|redis| redis.set("foo", "bar") }
131
+ Rhod.with_redis {|redis| redis.set("foo", "bar") }
132
+ # => "OK"
237
133
  ```
238
134
 
239
135
  The connection is always the first argument passed into the block, the other arguments are passed in their original order after.
@@ -241,7 +137,7 @@ The connection is always the first argument passed into the block, the other arg
241
137
  ```ruby
242
138
  key = "foo"
243
139
  value = "bar"
244
- Rhod.execute(key, value, :pool => :redis) {|redis, k, v| redis.set(k, v) }
140
+ Rhod.with_redis(key, value) {|redis, k, v| redis.set(k, v) }
245
141
  ```
246
142
 
247
143
  ## Contributing
@@ -1,27 +1,17 @@
1
+ require 'connection_pool'
1
2
  require_relative "rhod/version"
2
3
  require_relative "rhod/backoffs"
3
4
  require_relative "rhod/command"
4
- require 'connection_pool'
5
+ require_relative "rhod/profile"
5
6
 
6
7
  module Rhod
8
+
7
9
  def self.execute(*args, &block)
8
- Rhod::Command.execute(*args, &block)
10
+ Rhod.with_default(*args, &block)
9
11
  end
10
12
 
11
- class << self
12
- attr_accessor :defaults
13
-
14
- attr_accessor :connection_pools
13
+ def self.create_profile(name, options={})
14
+ Rhod::Profile.new(name, options)
15
15
  end
16
16
 
17
- self.defaults = {
18
- retries: 0,
19
- backoffs: Rhod::Backoffs.default,
20
- fallback: nil,
21
- }
22
-
23
- self.connection_pools = {
24
- default: ConnectionPool.new(size: 1, timeout: 0) { nil }
25
- }
26
-
27
17
  end
@@ -3,76 +3,40 @@ module Rhod::Backoffs
3
3
  extend self
4
4
 
5
5
  def backoff_sugar_to_enumerator(backoff)
6
- if backoff.is_a?(Enumerator)
6
+ if backoff.is_a?(Rhod::Backoffs::Backoff)
7
7
  backoff
8
8
  elsif backoff.is_a?(Numeric)
9
- constant_backoff(backoff)
9
+ Rhod::Backoffs::Constant.new(backoff)
10
10
  elsif backoff.is_a?(Range)
11
- random_backoffs(backoff)
11
+ Rhod::Backoffs::Random.new(backoff)
12
12
  elsif backoff.is_a?(String)
13
13
  n = (backoff[1..-1].to_f)
14
14
  case backoff[0]
15
15
  when "^"
16
- expoential_backoffs(n)
16
+ Rhod::Backoffs::Exponential.new(n)
17
17
  when "l"
18
- logarithmic_backoffs(n)
18
+ Rhod::Backoffs::Logarithmic.new(n)
19
19
  when "r"
20
20
  min = backoff[1..-1].split("..")[0].to_f
21
21
  max = backoff[1..-1].split("..")[1].to_f
22
- random_backoffs((min..max))
22
+ Rhod::Backoffs::Random.new((min..max))
23
23
  end
24
24
  elsif backoff.is_a?(Symbol)
25
25
  case backoff
26
26
  when :^
27
- expoential_backoffs
27
+ Rhod::Backoffs::Exponential.new(0)
28
28
  when :l
29
- logarithmic_backoffs
29
+ Rhod::Backoffs::Logarithmic.new(1.3)
30
30
  when :r
31
- random_backoffs
32
- end
33
- end
34
- end
35
-
36
- # Returns a generator of a expoentially increasing series starting at n
37
- def expoential_backoffs(n=1)
38
- Enumerator.new do |yielder|
39
- x = (n - 1)
40
- loop do
41
- x += 1
42
- yielder << 2.0**x
43
- end
44
- end
45
- end
46
-
47
- # Returns a generator of a logarithmicly increasing series starting at n
48
- def logarithmic_backoffs(n=0.3)
49
- Enumerator.new do |yielder|
50
- x = n
51
- loop do
52
- x += 1
53
- yielder << Math.log2(x**2)
54
- end
55
- end
56
- end
57
- alias default logarithmic_backoffs
58
-
59
- # Always the same backoff
60
- def constant_backoff(n)
61
- Enumerator.new do |yielder|
62
- loop do
63
- yielder << n
64
- end
65
- end
66
- end
67
-
68
- # Returns a generator of random numbers falling inside of a range
69
- def random_backoffs(range=(0..10))
70
- float_range = (range.min.to_f..range.max.to_f)
71
- Enumerator.new do |yielder|
72
- loop do
73
- yielder << rand(float_range)
31
+ Rhod::Backoffs::Random.new(0..10)
74
32
  end
75
33
  end
76
34
  end
77
35
 
78
36
  end
37
+
38
+ require_relative 'backoffs/backoff.rb'
39
+ require_relative 'backoffs/constant.rb'
40
+ require_relative 'backoffs/exponential.rb'
41
+ require_relative 'backoffs/logarithmic.rb'
42
+ require_relative 'backoffs/random.rb'
@@ -0,0 +1,16 @@
1
+ class Rhod::Backoffs::Backoff
2
+ attr_reader :state
3
+
4
+ def initialize(state = nil)
5
+ @state = state
6
+ end
7
+
8
+ def iterate
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def next
13
+ @state, result = iterate(state)
14
+ result
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ class Rhod::Backoffs::Constant < Rhod::Backoffs::Backoff
2
+ def iterate(state)
3
+ [state, state]
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Rhod::Backoffs::Exponential < Rhod::Backoffs::Backoff
2
+ def iterate(state)
3
+ [state + 1, 2.0**(state)]
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Rhod::Backoffs::Logarithmic < Rhod::Backoffs::Backoff
2
+ def iterate(state)
3
+ [state + 1, Math.log2((state)**2)]
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class Rhod::Backoffs::Random < Rhod::Backoffs::Backoff
2
+ def iterate(state)
3
+ @float_range ||= (state.min.to_f..state.max.to_f)
4
+ [@float_range, rand(@float_range)]
5
+ end
6
+ end
@@ -10,17 +10,19 @@ class Rhod::Command
10
10
  @request = block
11
11
 
12
12
  @retries = opts[:retries]
13
- @retries ||= Rhod.defaults[:retries]
13
+ @retries ||= 0
14
14
  @attempts = 0
15
15
 
16
16
  @backoffs = Rhod::Backoffs.backoff_sugar_to_enumerator(opts[:backoffs])
17
- @backoffs ||= Rhod.defaults[:backoffs]
17
+ @backoffs ||= Rhod::Backoffs::Logarithmic.new(1.3)
18
18
 
19
19
  @fallback = opts[:fallback]
20
- @fallback ||= Rhod.defaults[:fallback]
21
20
 
22
- @pool = Rhod.connection_pools[opts[:pool]]
23
- @pool ||= Rhod.connection_pools[:default]
21
+ @pool = opts[:pool]
22
+ @pool ||= ConnectionPool.new(size: 1, timeout: 0) { nil }
23
+
24
+ @exceptions = opts[:exceptions]
25
+ @exceptions ||= EXCEPTIONS
24
26
  end
25
27
 
26
28
  ### Class methods
@@ -40,7 +42,7 @@ class Rhod::Command
40
42
 
41
43
  @request.call(*@args)
42
44
  end
43
- rescue *EXCEPTIONS
45
+ rescue *@exceptions
44
46
  @attempts += 1
45
47
  if @attempts <= @retries
46
48
  sleep(@backoffs.next)
@@ -0,0 +1,37 @@
1
+ class Rhod::Profile < Hash
2
+ @@profiles = {}
3
+
4
+ def initialize(name, options={})
5
+ # When creating new profiles, copy from the global default, incase it was customized.
6
+ if @@profiles[:default]
7
+ default = @@profiles[:default].dup
8
+ else
9
+ default = {}
10
+ end
11
+
12
+ default.each {|k,v| self[k] = v }
13
+
14
+ options.each {|k,v| self[k] = v }
15
+
16
+ # Syntax sugar: named .with_#{profile} methods on this class and the module
17
+ @@profiles[name] = self
18
+
19
+ self.class.__send__(:define_method, :"with_#{name}") do |*args, &block|
20
+ Rhod::Command.execute(*args, @@profiles[name], &block)
21
+ end
22
+
23
+ Rhod.class.__send__(:define_method, :"with_#{name}") do |*args, &block|
24
+ Rhod::Command.execute(*args, @@profiles[name], &block)
25
+ end
26
+
27
+ self
28
+ end
29
+ end
30
+
31
+ Rhod::Profile.new(:default,
32
+ retries: 0,
33
+ backoffs: Rhod::Backoffs::Logarithmic.new(1.3),
34
+ fallback: nil,
35
+ pool: ConnectionPool.new(size: 1, timeout: 0) { nil },
36
+ exceptions: [Exception, StandardError],
37
+ )
@@ -1,3 +1,3 @@
1
1
  module Rhod
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -4,7 +4,7 @@ require File.expand_path(File.dirname(__FILE__) + '/helper')
4
4
  describe Rhod::Backoffs do
5
5
  describe "backoff_sugar_to_enumerator" do
6
6
  it "returns enumerators as is" do
7
- e = Rhod::Backoffs.constant_backoff(0)
7
+ e = Rhod::Backoffs::Constant.new(0)
8
8
  Rhod::Backoffs.backoff_sugar_to_enumerator(e).must_equal e
9
9
  end
10
10
 
@@ -14,35 +14,59 @@ describe Rhod::Backoffs do
14
14
  end
15
15
 
16
16
  it "generates expoential backoffs with '^' syntax" do
17
- Rhod::Backoffs.backoff_sugar_to_enumerator("^2.0").take(3).must_equal [4.0, 8.0, 16.0]
17
+ results = []
18
+ eb = Rhod::Backoffs.backoff_sugar_to_enumerator("^2.0")
19
+
20
+ 3.times { results << eb.next }
21
+
22
+ results.must_equal [4.0, 8.0, 16.0]
18
23
  end
19
24
 
20
25
  it "generates logarithmic backoffs with 'l' syntax" do
21
- Rhod::Backoffs.backoff_sugar_to_enumerator("l2.0").
22
- take(3).must_equal [3.169925001442312, 4.0, 4.643856189774724]
26
+ results = []
27
+ lb = Rhod::Backoffs.backoff_sugar_to_enumerator("l2.0")
28
+
29
+ 3.times { results << lb.next }
30
+
31
+ results.must_equal [2.0, 3.169925001442312, 4.0]
23
32
  end
24
33
 
25
34
  it "generates random backoffs with 'r' syntax" do
26
- sample = Rhod::Backoffs.backoff_sugar_to_enumerator("r1..2").
27
- take(3)
28
- sample.min.floor.must_equal 1
29
- sample.max.ceil.must_equal 2
35
+ results = []
36
+ rb = Rhod::Backoffs.backoff_sugar_to_enumerator("r1..2")
37
+
38
+ 10.times { results << rb.next }
39
+
40
+ results.min.floor.must_equal 1
41
+ results.max.ceil.must_equal 2
30
42
  end
31
43
 
32
44
  it "generates expoential backoffs with :^ syntax" do
33
- Rhod::Backoffs.backoff_sugar_to_enumerator(:^).take(3).must_equal [2.0, 4.0, 8.0]
45
+ results = []
46
+ eb = Rhod::Backoffs.backoff_sugar_to_enumerator(:^)
47
+
48
+ 3.times { results << eb.next }
49
+
50
+ results.must_equal [1.0, 2.0, 4.0]
34
51
  end
35
52
 
36
53
  it "generates logarithmic backoffs with :l syntax" do
37
- Rhod::Backoffs.backoff_sugar_to_enumerator(:l).
38
- take(3).must_equal [0.7570232465074598, 2.403267722339301, 3.444932048942182]
54
+ results = []
55
+ lb = Rhod::Backoffs.backoff_sugar_to_enumerator(:l)
56
+
57
+ 3.times { results << lb.next }
58
+
59
+ results.must_equal [0.7570232465074598, 2.403267722339301, 3.444932048942182]
39
60
  end
40
61
 
41
62
  it "generates random backoffs with :r syntax" do
42
- sample = Rhod::Backoffs.backoff_sugar_to_enumerator(:r).
43
- take(100)
44
- sample.min.floor.must_equal 0
45
- sample.max.ceil.must_equal 10
63
+ results = []
64
+ rb = Rhod::Backoffs.backoff_sugar_to_enumerator(:r)
65
+
66
+ 100.times { results << rb.next }
67
+
68
+ results.min.floor.must_equal 0
69
+ results.max.ceil.must_equal 10
46
70
  end
47
71
  end
48
72
  end
@@ -34,7 +34,7 @@ describe Rhod::Command do
34
34
  backoff = MiniTest::Mock.new
35
35
  backoff.expect(:next, 0)
36
36
 
37
- Rhod::Backoffs.stub(:constant_backoff, backoff) do
37
+ Rhod::Backoffs::Constant.stub(:new, backoff) do
38
38
  begin
39
39
  Rhod::Command.new(:retries => 1, :backoffs => 0) do
40
40
  val += 1
@@ -75,14 +75,14 @@ describe Rhod::Command do
75
75
 
76
76
  describe "with connection pools" do
77
77
  it "uses the provided pool" do
78
- Rhod.connection_pools[:test] = ConnectionPool.new(size: 1, timeout: 0) { :conn }
78
+ pool = ConnectionPool.new(size: 1, timeout: 0) { :conn }
79
79
  Rhod::Command.new {|a| a}.execute.must_equal nil
80
- Rhod::Command.new(pool: :test) {|a| a}.execute.must_equal :conn
80
+ Rhod::Command.new(pool: pool) {|a| a}.execute.must_equal :conn
81
81
  end
82
82
 
83
83
  it "correctly handles arguements" do
84
- Rhod.connection_pools[:test] = ConnectionPool.new(size: 1, timeout: 0) { :conn }
85
- Rhod::Command.new(1, pool: :test) {|a, b| [a,b]}.execute.must_equal [:conn, 1]
84
+ pool = ConnectionPool.new(size: 1, timeout: 0) { :conn }
85
+ Rhod::Command.new(1, pool: pool) {|a, b| [a,b]}.execute.must_equal [:conn, 1]
86
86
  end
87
87
  end
88
88
 
@@ -0,0 +1,30 @@
1
+ require 'minitest/autorun'
2
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
3
+
4
+ describe Rhod::Profile do
5
+ describe "defaults" do
6
+ it "always has them" do
7
+ assert_instance_of Rhod::Profile, Rhod::Profile.class_variable_get(:@@profiles)[:default]
8
+ defined?(Rhod.with_default).must_equal "method"
9
+ defined?(Rhod::Profile.with_default).must_equal "method"
10
+ end
11
+ end
12
+
13
+ describe "self.new" do
14
+ it "copies missing attributes from the defaults" do
15
+ Rhod::Profile.new(:test1, retries: 55 )
16
+ Rhod::Profile.class_variable_get(:@@profiles)[:test1][:retries].must_equal 55
17
+ Rhod::Profile.class_variable_get(:@@profiles)[:test1][:exceptions].must_equal [Exception, StandardError]
18
+ end
19
+
20
+ it "creates a new method on itself and the module for new profiles" do
21
+ defined?(Rhod.with_test2).must_equal nil
22
+ defined?(Rhod::Profile.with_test2).must_equal nil
23
+
24
+ Rhod::Profile.new(:test2)
25
+
26
+ defined?(Rhod.with_test2).must_equal "method"
27
+ defined?(Rhod::Profile.with_test2).must_equal "method"
28
+ end
29
+ end
30
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhod
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Bergeron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-20 00:00:00.000000000 Z
11
+ date: 2013-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -103,18 +103,26 @@ extra_rdoc_files: []
103
103
  files:
104
104
  - .gitignore
105
105
  - .pryrc
106
+ - Changes.md
106
107
  - Gemfile
107
108
  - LICENSE.txt
108
109
  - README.md
109
110
  - Rakefile
110
111
  - lib/rhod.rb
111
112
  - lib/rhod/backoffs.rb
113
+ - lib/rhod/backoffs/backoff.rb
114
+ - lib/rhod/backoffs/constant.rb
115
+ - lib/rhod/backoffs/exponential.rb
116
+ - lib/rhod/backoffs/logarithmic.rb
117
+ - lib/rhod/backoffs/random.rb
112
118
  - lib/rhod/command.rb
119
+ - lib/rhod/profile.rb
113
120
  - lib/rhod/version.rb
114
121
  - rhod.gemspec
115
122
  - test/helper.rb
116
123
  - test/test_backoffs.rb
117
124
  - test/test_command.rb
125
+ - test/test_profile.rb
118
126
  homepage: https://github.com/dinedal/rhod
119
127
  licenses:
120
128
  - MIT
@@ -143,3 +151,4 @@ test_files:
143
151
  - test/helper.rb
144
152
  - test/test_backoffs.rb
145
153
  - test/test_command.rb
154
+ - test/test_profile.rb