cottus 0.2.0 → 0.3.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: 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
  - - '>='