cottus 0.2.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 362f67d0f8c8fd3245548533ae68bbcf1e012957
4
- data.tar.gz: be8e86a230fac1d891506d1616a84745b3c6f7d4
3
+ metadata.gz: b664ce094bd30b48d6e6a4f0bc136d9b78a27e0e
4
+ data.tar.gz: 6cedfbfa25af3845515d43ba47305ea0402d3c8c
5
5
  SHA512:
6
- metadata.gz: 5c7139181bc75a318f1ad87e5989c7d8c76d67fa44ed512a628aad0be3a3c227bd5a4bb745a7879b2b980a52170a5528f0c43e7b89217cb8ecf5454a1a7b3c93
7
- data.tar.gz: dda18ac01482b6d1885517dbfd231d637e590e1c930ef42409d66faefd5e1b7a9a6f2daeb7bf0184d3df9316cf3686ae3ce1758948695916aef0c2268d626e1e
6
+ metadata.gz: dc7a3b6eccaab7606cc74397f3c5b4a1d7c8b545938aebbec7ec0642512282b5d60c447316239668cae5e8326e40bf1e5583c36f8533d84c87186a35dbe80235
7
+ data.tar.gz: f80fc8cc0939e4980d43e9315e2290a3c19200abb63cbdcc9c056c26e0d0be7e4cf204cb0918dee4c8fc6a36c64d968080b4a3849528fe9d588107314cea3342
data/README.md CHANGED
@@ -36,17 +36,17 @@ response = client.post('/any/path', :query => {:id => 1337}, :body => { :attribu
36
36
  puts response.body, response.code, response.message, response.headers.inspect
37
37
  ```
38
38
 
39
- That's about it! Cottus exposes almost all of the same methods with the same semantics as
40
- HTTParty does, with the exception of ```HTTParty#copy```.
39
+ That's about it! Cottus exposes almost all of the same methods with similar semantics as
40
+ Excon does.
41
41
 
42
42
  ## Strategy
43
43
 
44
- A "Strategy" is merely a class implementing an ```execute``` method that is
45
- responsible for carrying out the action specified by the passed ```meth```
44
+ A "Strategy" is merely a class implementing an `execute` method that is
45
+ responsible for carrying out the action specified by the passed `meth`
46
46
  argument.
47
47
 
48
- The Strategy class must however also implement an ```#initialize``` method which
49
- takes two parameters: ```connections``` and an ```options``` hash:
48
+ The Strategy class must however also implement an `#initialize` method which
49
+ takes two parameters: `connections` and an `options` hash:
50
50
 
51
51
  ```ruby
52
52
  class SomeStrategy
@@ -59,7 +59,7 @@ class SomeStrategy
59
59
  end
60
60
  ```
61
61
 
62
- If you don't mind inheritance there's a base class (```Cottus::Strategy```) that
62
+ If you don't mind inheritance there's a base class (`Cottus::Strategy`) that
63
63
  you can inherit from and the above class would instead become:
64
64
 
65
65
  ```ruby
@@ -71,13 +71,13 @@ end
71
71
  ```
72
72
 
73
73
  If you'd like to do some initialization on your own and override
74
- ```#initialize``` make sure to call ```#super``` or set the required instance
75
- variable (```@connections```) on your own.
74
+ `#initialize` make sure to call `#super` or set the required instance
75
+ variable (`@connections`) on your own.
76
76
 
77
77
  It should be noted that I haven't decided on how strategies should be working to
78
78
  a 100% yet, so this might change in future releases.
79
79
 
80
- See ```lib/cottus/strategies.rb``` for further examples.
80
+ See `lib/cottus/strategies.rb` for further examples.
81
81
 
82
82
  ### Using your own strategy
83
83
 
@@ -92,7 +92,7 @@ client = Cottus::Client.new(['http://n1.com', 'http://n2.com'], :strategy => MyS
92
92
 
93
93
  Want some additional options passed when your strategy is initialized?
94
94
 
95
- No problem! Pass them into the ```strategy_options``` sub-hash of the options
95
+ No problem! Pass them into the `strategy_options` sub-hash of the options
96
96
  hash to the client.
97
97
 
98
98
  ```ruby
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'httparty'
3
+ require 'excon'
4
4
 
5
5
  require 'cottus/forward'
6
6
  require 'cottus/client'
@@ -21,7 +21,7 @@ module Cottus
21
21
 
22
22
  def create_connections(hosts)
23
23
  hosts = hosts.is_a?(String) ? hosts.split(',') : hosts
24
- hosts.map { |host| Connection.new(http, host) }
24
+ hosts.map { |host| Connection.new(Excon.new(host)) }
25
25
  end
26
26
 
27
27
  def create_strategy(options)
@@ -29,9 +29,5 @@ module Cottus
29
29
  strategy_impl = options[:strategy] || RoundRobinStrategy
30
30
  strategy_impl.new(connections, strategy_options)
31
31
  end
32
-
33
- def http
34
- HTTParty
35
- end
36
32
  end
37
33
  end
@@ -8,14 +8,18 @@ module Cottus
8
8
 
9
9
  attr_reader :host
10
10
 
11
- def initialize(*args)
12
- @http, @host = *args
11
+ def initialize(connection)
12
+ @connection = connection
13
+ end
14
+
15
+ def host
16
+ @connection.data[:host]
13
17
  end
14
18
 
15
19
  private
16
20
 
17
- def wrapper(verb, path, options={}, &blk)
18
- @http.send(verb, @host + path, options, &blk)
21
+ def wrapper(verb, path, options={})
22
+ @connection.send(verb, options.merge({path: path}))
19
23
  end
20
24
  end
21
25
  end
@@ -7,11 +7,11 @@ module Cottus
7
7
  to, through = options.values_at(:to, :through)
8
8
 
9
9
  args.each do |verb|
10
- define_method(verb) do |path, opts={}, &blk|
10
+ define_method(verb) do |path, opts={}|
11
11
  if to && through
12
- instance_variable_get(to).send(through, verb, path, opts, &blk)
12
+ instance_variable_get(to).send(through, verb, path, opts)
13
13
  else
14
- self.send(to, verb, path, opts, &blk)
14
+ self.send(to, verb, path, opts)
15
15
  end
16
16
  end
17
17
  end
@@ -4,6 +4,7 @@ module Cottus
4
4
 
5
5
  VALID_EXCEPTIONS = [
6
6
  Timeout::Error,
7
+ Excon::Errors::Timeout,
7
8
  Errno::ECONNREFUSED,
8
9
  Errno::ETIMEDOUT,
9
10
  Errno::ECONNRESET
@@ -14,7 +15,7 @@ module Cottus
14
15
  @connections = connections
15
16
  end
16
17
 
17
- def execute(meth, path, options={}, &block)
18
+ def execute(meth, path, options={})
18
19
  raise NotImplementedError, 'implement me in subclass'
19
20
  end
20
21
  end
@@ -27,11 +28,11 @@ module Cottus
27
28
  @mutex = Mutex.new
28
29
  end
29
30
 
30
- def execute(meth, path, options={}, &block)
31
+ def execute(meth, path, options={})
31
32
  tries = 0
32
33
 
33
34
  begin
34
- next_connection.send(meth, path, options, &block)
35
+ next_connection.send(meth, path, options)
35
36
  rescue *VALID_EXCEPTIONS => e
36
37
  if tries >= @connections.count
37
38
  raise e
@@ -60,12 +61,12 @@ module Cottus
60
61
  @timeouts = options[:timeouts] || [1, 3, 5]
61
62
  end
62
63
 
63
- def execute(meth, path, options={}, &block)
64
+ def execute(meth, path, options={})
64
65
  tries = 0
65
66
  starting_connection = connection = next_connection
66
67
 
67
68
  begin
68
- connection.send(meth, path, options, &block)
69
+ connection.send(meth, path, options)
69
70
  rescue *VALID_EXCEPTIONS => e
70
71
  if tries < @timeouts.size
71
72
  sleep @timeouts[tries]
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Cottus
4
- VERSION = '0.2.0'.freeze
4
+ VERSION = '0.3.0'.freeze
5
5
  end
@@ -6,7 +6,7 @@ module Cottus
6
6
  describe 'Client acceptance spec' do
7
7
  shared_examples 'exception handling' do
8
8
  context 'exceptions' do
9
- context 'Timeout::Error' do
9
+ context 'Excon::Errors::Timeout' do
10
10
  it 'attempts to use each host until one succeeds' do
11
11
  stub_request(verb, 'http://localhost:1234/some/path').to_timeout
12
12
  stub_request(verb, 'http://localhost:12345/some/path').to_timeout
@@ -21,7 +21,7 @@ module Cottus
21
21
  stub_request(verb, 'http://localhost:12345/some/path').to_timeout
22
22
  stub_request(verb, 'http://localhost:12343/some/path').to_timeout
23
23
 
24
- expect { client.send(verb, '/some/path') }.to raise_error(Timeout::Error)
24
+ expect { client.send(verb, '/some/path') }.to raise_error(Excon::Errors::Timeout)
25
25
  end
26
26
  end
27
27
 
@@ -147,16 +147,6 @@ module Cottus
147
147
  end
148
148
  end
149
149
 
150
- describe '#move' do
151
- include_examples 'load balancing' do
152
- let(:verb) { :move }
153
- end
154
-
155
- include_examples 'exception handling' do
156
- let(:verb) { :move }
157
- end
158
- end
159
-
160
150
  describe '#options' do
161
151
  include_examples 'load balancing' do
162
152
  let(:verb) { :options }
@@ -166,17 +156,5 @@ module Cottus
166
156
  let(:verb) { :options }
167
157
  end
168
158
  end
169
-
170
- describe '#copy' do
171
- pending do
172
- include_examples 'load balancing' do
173
- let(:verb) { :options }
174
- end
175
-
176
- include_examples 'exception handling' do
177
- let(:verb) { :options }
178
- end
179
- end
180
- end
181
159
  end
182
160
  end
@@ -6,13 +6,13 @@ module Cottus
6
6
  describe Client do
7
7
  describe '#initialize' do
8
8
  it 'accepts an array of hosts w/ ports' do
9
- client = described_class.new(['host1:123', 'host2:125'])
10
- expect(client.hosts).to eq ['host1:123', 'host2:125']
9
+ client = described_class.new(['http://host1:123', 'http://host2:125'])
10
+ expect(client.hosts).to eq ['host1', 'host2']
11
11
  end
12
12
 
13
13
  it 'accepts a connection string w/ ports' do
14
- client = described_class.new('host1:1255,host2:1255,host3:1255')
15
- expect(client.hosts).to eq ['host1:1255', 'host2:1255', 'host3:1255']
14
+ client = described_class.new('http://host1:1255,http://host2:1255,http://host3:1255')
15
+ expect(client.hosts).to eq ['host1', 'host2', 'host3']
16
16
  end
17
17
  end
18
18
 
@@ -8,16 +8,20 @@ module Cottus
8
8
  described_class.new(connections)
9
9
  end
10
10
 
11
- let :http do
11
+ let :first do
12
12
  double(:http, get: nil)
13
13
  end
14
14
 
15
- let :hosts do
16
- ['http://n1.com', 'http://n2.com']
15
+ let :second do
16
+ double(:http, get: nil)
17
+ end
18
+
19
+ let :third do
20
+ double(:http, get: nil)
17
21
  end
18
22
 
19
23
  let :connections do
20
- hosts.map { |host| Connection.new(http, host) }
24
+ [first, second, third]
21
25
  end
22
26
 
23
27
  describe '#execute' do
@@ -29,47 +33,47 @@ module Cottus
29
33
 
30
34
  shared_examples 'a round-robin strategy' do
31
35
  context 'with a single host' do
32
- let :hosts do
33
- ['n1']
36
+ let :connections do
37
+ [first]
34
38
  end
35
39
 
36
40
  it 'uses the single host for the first request' do
37
41
  strategy.execute(:get, '/some/path', query: { query: 1 })
38
42
 
39
- expect(http).to have_received(:get).with('n1/some/path', query: { query: 1 }).once
43
+ expect(first).to have_received(:get).with('/some/path', query: { query: 1 }).once
40
44
  end
41
45
 
42
46
  it 'uses the single host for the second request' do
43
47
  2.times { strategy.execute(:get, '/some/path', query: { query: 1 }) }
44
48
 
45
- expect(http).to have_received(:get).with('n1/some/path', query: { query: 1 }).twice
49
+ expect(first).to have_received(:get).with('/some/path', query: { query: 1 }).twice
46
50
  end
47
51
  end
48
52
 
49
53
  context 'with several hosts' do
50
- let :hosts do
51
- ['n1', 'n2', 'n3']
54
+ let :connections do
55
+ [first, second, third]
52
56
  end
53
57
 
54
58
  it 'uses the first host for the first request' do
55
59
  strategy.execute(:get, '/some/path', query: { query: 1 })
56
60
 
57
- expect(http).to have_received(:get).with('n1/some/path', query: { query: 1 }).once
61
+ expect(first).to have_received(:get).with('/some/path', query: { query: 1 }).once
58
62
  end
59
63
 
60
64
  it 'uses the second host for the second request' do
61
65
  2.times { strategy.execute(:get, '/some/path', query: { query: 1 }) }
62
66
 
63
- expect(http).to have_received(:get).with('n1/some/path', query: { query: 1 }).once
64
- expect(http).to have_received(:get).with('n2/some/path', query: { query: 1 }).once
67
+ expect(first).to have_received(:get).with('/some/path', query: { query: 1 }).once
68
+ expect(second).to have_received(:get).with('/some/path', query: { query: 1 }).once
65
69
  end
66
70
 
67
71
  it 'uses each host in turn' do
68
72
  3.times { strategy.execute(:get, '/some/path', query: { query: 1 }) }
69
73
 
70
- expect(http).to have_received(:get).with('n1/some/path', query: { query: 1 }).once
71
- expect(http).to have_received(:get).with('n2/some/path', query: { query: 1 }).once
72
- expect(http).to have_received(:get).with('n3/some/path', query: { query: 1 }).once
74
+ expect(first).to have_received(:get).with('/some/path', query: { query: 1 }).once
75
+ expect(second).to have_received(:get).with('/some/path', query: { query: 1 }).once
76
+ expect(third).to have_received(:get).with('/some/path', query: { query: 1 }).once
73
77
  end
74
78
  end
75
79
  end
@@ -79,12 +83,16 @@ module Cottus
79
83
  described_class.new(connections)
80
84
  end
81
85
 
82
- let :http do
86
+ let :first do
83
87
  double(:http, get: nil)
84
88
  end
85
89
 
86
- let :connections do
87
- hosts.map { |host| Connection.new(http, host) }
90
+ let :second do
91
+ double(:http, get: nil)
92
+ end
93
+
94
+ let :third do
95
+ double(:http, get: nil)
88
96
  end
89
97
 
90
98
  describe '#execute' do
@@ -96,31 +104,31 @@ module Cottus
96
104
  [Timeout::Error, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET].each do |error|
97
105
  context "when #{error} is raised" do
98
106
  context 'with a single host' do
99
- let :hosts do
100
- ['n1']
107
+ let :connections do
108
+ [first]
101
109
  end
102
110
 
103
111
  it 'gives up' do
104
- hosts.each { |h| http.stub(:get).with("#{h}/some/path", {}).and_raise(error) }
112
+ connections.each { |conn| conn.stub(:get).with('/some/path', {}).and_raise(error) }
105
113
 
106
114
  expect { strategy.execute(:get, '/some/path') }.to raise_error(error)
107
115
  end
108
116
  end
109
117
 
110
118
  context 'with several hosts' do
111
- let :hosts do
112
- ['n1', 'n2', 'n3']
119
+ let :connections do
120
+ [first, second, third]
113
121
  end
114
122
 
115
123
  it 'attempts to use each host until one succeeds' do
116
- ['n1', 'n2'].each { |h| http.stub(:get).with("#{h}/some/path", {}).and_raise(error) }
124
+ [first, second].each { |conn| conn.stub(:get).with('/some/path', {}).and_raise(error) }
117
125
 
118
126
  strategy.execute(:get, '/some/path')
119
- expect(http).to have_received(:get).with('n3/some/path', {})
127
+ expect(third).to have_received(:get).with('/some/path', {})
120
128
  end
121
129
 
122
130
  it 'gives up after trying all hosts' do
123
- hosts.each { |h| http.stub(:get).with("#{h}/some/path", {}).and_raise(error) }
131
+ connections.each { |conn| conn.stub(:get).with('/some/path', {}).and_raise(error) }
124
132
 
125
133
  expect { strategy.execute(:get, '/some/path') }.to raise_error(error)
126
134
  end
@@ -136,12 +144,16 @@ module Cottus
136
144
  described_class.new(connections, timeouts: [0, 0, 0])
137
145
  end
138
146
 
139
- let :http do
147
+ let :first do
140
148
  double(:http, get: nil)
141
149
  end
142
150
 
143
- let :connections do
144
- hosts.map { |host| Connection.new(http, host) }
151
+ let :second do
152
+ double(:http, get: nil)
153
+ end
154
+
155
+ let :third do
156
+ double(:http, get: nil)
145
157
  end
146
158
 
147
159
  describe '#execute' do
@@ -153,20 +165,20 @@ module Cottus
153
165
  [Timeout::Error, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET].each do |error|
154
166
  context "when #{error} is raised" do
155
167
  context 'with a single host' do
156
- let :hosts do
157
- ['n1']
168
+ let :connections do
169
+ [first]
158
170
  end
159
171
 
160
172
  it 'uses the single host for three consecutive exceptions' do
161
- expect(http).to receive(:get).with('n1/some/path', {}).exactly(3).times.and_raise(error)
162
- expect(http).to receive(:get).with('n1/some/path', {}).once
173
+ expect(first).to receive(:get).with('/some/path', {}).exactly(3).times.and_raise(error)
174
+ expect(first).to receive(:get).with('/some/path', {}).once
163
175
  expect(strategy).to receive(:sleep).with(0).exactly(3).times
164
176
 
165
177
  strategy.execute(:get, '/some/path')
166
178
  end
167
179
 
168
180
  it 'gives up after three retries' do
169
- expect(http).to receive(:get).with('n1/some/path', {}).exactly(4).times.and_raise(error)
181
+ expect(first).to receive(:get).with('/some/path', {}).exactly(4).times.and_raise(error)
170
182
  expect(strategy).to receive(:sleep).with(0).exactly(3).times
171
183
 
172
184
  expect { strategy.execute(:get, '/some/path') }.to raise_error(error)
@@ -174,21 +186,21 @@ module Cottus
174
186
  end
175
187
 
176
188
  context 'with several hosts' do
177
- let :hosts do
178
- ['n1', 'n2', 'n3']
189
+ let :connections do
190
+ [first, second, third]
179
191
  end
180
192
 
181
193
  it 'uses the same host for three consecutive exceptions' do
182
- expect(http).to receive(:get).with('n1/some/path', {}).exactly(3).times.and_raise(error)
183
- expect(http).to receive(:get).with('n1/some/path', {}).once
194
+ expect(first).to receive(:get).with('/some/path', {}).exactly(3).times.and_raise(error)
195
+ expect(first).to receive(:get).with('/some/path', {}).once
184
196
  expect(strategy).to receive(:sleep).with(0).exactly(3).times
185
197
 
186
198
  strategy.execute(:get, '/some/path')
187
199
  end
188
200
 
189
201
  it 'switches host after three retries' do
190
- expect(http).to receive(:get).with('n1/some/path', {}).exactly(4).times.and_raise(error)
191
- expect(http).to receive(:get).with('n2/some/path', {}).once
202
+ expect(first).to receive(:get).with('/some/path', {}).exactly(4).times.and_raise(error)
203
+ expect(second).to receive(:get).with('/some/path', {}).once
192
204
  expect(strategy).to receive(:sleep).with(0).exactly(3).times
193
205
 
194
206
  strategy.execute(:get, '/some/path')
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cottus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mathias Söderberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-12 00:00:00.000000000 Z
11
+ date: 2013-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: httparty
14
+ name: excon
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - '>='