rhod 0.0.2 → 0.0.3

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: 48eaf0e214a15e8bbedf592f83cdac4f5ad24af8
4
- data.tar.gz: c58dedc35eb28bd9247516b64dee33d8083e69ae
3
+ metadata.gz: 99aa65709753429dc68b3979f9397bf2502e13ad
4
+ data.tar.gz: cd2856de21b568e00fa7bb7b097125ff722704b5
5
5
  SHA512:
6
- metadata.gz: 67aca7d1a71afb19bc469c07ad193054c7df1ab1aa0e31dae5ed522bd9b04eb91cec3fea0f6d259c8f3c3ef0673e46ee8f82468ae50ecbb64029c269ee9a1f3f
7
- data.tar.gz: 8cb15b2867eb6b00c1574841508e31317b8791b0f16e545b4a7df6da7ed5759c2a56b4a24ae0b2d088e795d3bde087c02960bd2e29f68b54369098aa7bc1547a
6
+ metadata.gz: 2245e308b5b535497b54e24681d7f512ca906b3dd1936897568b2022715063b66ed972ccb33cf0f68efdd81df5ec970533f0e67845aa01cbebd4e11762de4217
7
+ data.tar.gz: f8b786cde49e380879e0339513d9470f8a9c222e62e3f21eea915a3f821931b43e1b4a22752f64a9fdc8d4de8c76483b961f5fcc6a5326f58bf12f8480301df4
data/README.md CHANGED
@@ -39,6 +39,17 @@ Or install it yourself as:
39
39
 
40
40
  $ gem install rhod
41
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
+ ```
52
+
42
53
  ## Usage
43
54
 
44
55
  Rhod has a very simple API. Design your application as you would normally, then enclose network accessing portions of your code with:
@@ -60,6 +71,29 @@ require 'rhod'
60
71
  Rhod.execute { open("http://google.com").read }
61
72
  ```
62
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
+
63
97
  ### Retries with and without backoffs
64
98
 
65
99
  #### Idempotence Caution
@@ -117,6 +151,18 @@ Rhod.execute(:retries => 10, :backoffs => 0) do
117
151
  end
118
152
  ```
119
153
 
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
155
+
156
+ ```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
163
+ ```
164
+
165
+
120
166
  ### Fail Silent
121
167
 
122
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.
@@ -176,6 +222,28 @@ search_engine_html = SearchEngineHTML.new
176
222
  search_engine_html.fetch
177
223
  ```
178
224
 
225
+ ## Connection Pools
226
+
227
+ Sometimes you're connecting to a remote reasource using a driver that doesn't support connection pooling, which will limit the amount of strain your application puts on that reasource, and allow for reuse of existing connections instead of increasing overhead by reconnecting each time. Connection Pool support in Rhod is provided by the [connection_pool](https://github.com/mperham/connection_pool) gem.
228
+
229
+ ```ruby
230
+ require 'rhod'
231
+ require 'redis'
232
+ require 'connection_pool'
233
+
234
+ Rhod.connection_pools[:redis] = ConnectionPool.new(size:3, timeout:5) { Redis.new }
235
+
236
+ Rhod.execute(:pool => :redis) {|redis| redis.set("foo", "bar") }
237
+ ```
238
+
239
+ The connection is always the first argument passed into the block, the other arguments are passed in their original order after.
240
+
241
+ ```ruby
242
+ key = "foo"
243
+ value = "bar"
244
+ Rhod.execute(key, value, :pool => :redis) {|redis, k, v| redis.set(k, v) }
245
+ ```
246
+
179
247
  ## Contributing
180
248
 
181
249
  1. Fork it
@@ -1,9 +1,27 @@
1
1
  require_relative "rhod/version"
2
2
  require_relative "rhod/backoffs"
3
3
  require_relative "rhod/command"
4
+ require 'connection_pool'
4
5
 
5
6
  module Rhod
6
7
  def self.execute(*args, &block)
7
8
  Rhod::Command.execute(*args, &block)
8
9
  end
10
+
11
+ class << self
12
+ attr_accessor :defaults
13
+
14
+ attr_accessor :connection_pools
15
+ end
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
+
9
27
  end
@@ -7,13 +7,19 @@ module Rhod::Backoffs
7
7
  backoff
8
8
  elsif backoff.is_a?(Numeric)
9
9
  constant_backoff(backoff)
10
+ elsif backoff.is_a?(Range)
11
+ random_backoffs(backoff)
10
12
  elsif backoff.is_a?(String)
11
- n = (backoff[1..-1].to_i)
13
+ n = (backoff[1..-1].to_f)
12
14
  case backoff[0]
13
15
  when "^"
14
16
  expoential_backoffs(n)
15
17
  when "l"
16
18
  logarithmic_backoffs(n)
19
+ when "r"
20
+ min = backoff[1..-1].split("..")[0].to_f
21
+ max = backoff[1..-1].split("..")[1].to_f
22
+ random_backoffs((min..max))
17
23
  end
18
24
  elsif backoff.is_a?(Symbol)
19
25
  case backoff
@@ -21,6 +27,8 @@ module Rhod::Backoffs
21
27
  expoential_backoffs
22
28
  when :l
23
29
  logarithmic_backoffs
30
+ when :r
31
+ random_backoffs
24
32
  end
25
33
  end
26
34
  end
@@ -46,6 +54,7 @@ module Rhod::Backoffs
46
54
  end
47
55
  end
48
56
  end
57
+ alias default logarithmic_backoffs
49
58
 
50
59
  # Always the same backoff
51
60
  def constant_backoff(n)
@@ -56,5 +65,14 @@ module Rhod::Backoffs
56
65
  end
57
66
  end
58
67
 
59
- alias default logarithmic_backoffs
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)
74
+ end
75
+ end
76
+ end
77
+
60
78
  end
@@ -10,13 +10,17 @@ class Rhod::Command
10
10
  @request = block
11
11
 
12
12
  @retries = opts[:retries]
13
- @retries ||= 0
13
+ @retries ||= Rhod.defaults[:retries]
14
14
  @attempts = 0
15
15
 
16
16
  @backoffs = Rhod::Backoffs.backoff_sugar_to_enumerator(opts[:backoffs])
17
- @backoffs ||= Rhod::Backoffs.default
17
+ @backoffs ||= Rhod.defaults[:backoffs]
18
18
 
19
19
  @fallback = opts[:fallback]
20
+ @fallback ||= Rhod.defaults[:fallback]
21
+
22
+ @pool = Rhod.connection_pools[opts[:pool]]
23
+ @pool ||= Rhod.connection_pools[:default]
20
24
  end
21
25
 
22
26
  ### Class methods
@@ -30,7 +34,12 @@ class Rhod::Command
30
34
 
31
35
  def execute
32
36
  begin
33
- @request.call(*@args)
37
+ @pool.with do |conn|
38
+ @args = [conn].concat(@args)
39
+ @args[0] == nil ? @args.shift : nil
40
+
41
+ @request.call(*@args)
42
+ end
34
43
  rescue *EXCEPTIONS
35
44
  @attempts += 1
36
45
  if @attempts <= @retries
@@ -1,3 +1,3 @@
1
1
  module Rhod
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -18,8 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_development_dependency "bundler", "~> 1.3"
21
- spec.add_development_dependency "rake"
21
+ spec.add_development_dependency "rake", "~> 10.0.4"
22
22
  spec.add_development_dependency "pry"
23
- spec.add_development_dependency "minitest"
24
- spec.add_development_dependency "turn"
23
+ spec.add_development_dependency "minitest", "~> 4.4.0"
24
+ spec.add_development_dependency "turn", "~> 0.9.6"
25
+
26
+ spec.add_dependency "connection_pool", "~> 1.0.0"
25
27
  end
@@ -22,6 +22,13 @@ describe Rhod::Backoffs do
22
22
  take(3).must_equal [3.169925001442312, 4.0, 4.643856189774724]
23
23
  end
24
24
 
25
+ 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
30
+ end
31
+
25
32
  it "generates expoential backoffs with :^ syntax" do
26
33
  Rhod::Backoffs.backoff_sugar_to_enumerator(:^).take(3).must_equal [2.0, 4.0, 8.0]
27
34
  end
@@ -30,5 +37,12 @@ describe Rhod::Backoffs do
30
37
  Rhod::Backoffs.backoff_sugar_to_enumerator(:l).
31
38
  take(3).must_equal [0.7570232465074598, 2.403267722339301, 3.444932048942182]
32
39
  end
40
+
41
+ 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
46
+ end
33
47
  end
34
48
  end
@@ -72,5 +72,19 @@ describe Rhod::Command do
72
72
  end
73
73
  end
74
74
  end
75
+
76
+ describe "with connection pools" do
77
+ it "uses the provided pool" do
78
+ Rhod.connection_pools[:test] = ConnectionPool.new(size: 1, timeout: 0) { :conn }
79
+ Rhod::Command.new {|a| a}.execute.must_equal nil
80
+ Rhod::Command.new(pool: :test) {|a| a}.execute.must_equal :conn
81
+ end
82
+
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]
86
+ end
87
+ end
88
+
75
89
  end
76
90
  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.2
4
+ version: 0.0.3
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-07 00:00:00.000000000 Z
11
+ date: 2013-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 10.0.4
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 10.0.4
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -56,30 +56,44 @@ dependencies:
56
56
  name: minitest
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 4.4.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 4.4.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: turn
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 0.9.6
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ~>
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 0.9.6
83
+ - !ruby/object:Gem::Dependency
84
+ name: connection_pool
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 1.0.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 1.0.0
83
97
  description:
84
98
  email:
85
99
  - paul.d.bergeron@gmail.com