faraday_connection_pool 0.0.1
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 +7 -0
- data/.gitignore +19 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +22 -0
- data/README.md +78 -0
- data/Rakefile +1 -0
- data/faraday_connection_pool.gemspec +25 -0
- data/lib/faraday_connection_pool.rb +82 -0
- data/lib/faraday_connection_pool/version.rb +3 -0
- data/script/proxy-server +3 -0
- data/script/server +3 -0
- data/script/test +6 -0
- data/test/adapters/net_http_pooled_test.rb +107 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2c8dc652b39beefa2f725ce45ce3023f49150b8a
|
4
|
+
data.tar.gz: 72034577546525481ec6ad29a66ea23f13d033c0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b497d71965dd9fe76005560d81cd3c320b128ebda5f78a37cd7303ec17a489cd9b1ee045c1c0749911bc17093880799a257f4fd7f95a3533fb85f7fa993d0964
|
7
|
+
data.tar.gz: dd89ee14b05f214f58ca007e7db0b5759f3477b87161e6f583dace1b5024a0c031093ed9b7493e63d0014f807a1e335f499244da4681792e744b0764c4a89811
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in faraday_connection_pool.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :test do
|
7
|
+
gem 'coveralls', :require => false
|
8
|
+
gem 'leftright', '>= 0.9', :require => false
|
9
|
+
gem 'mime-types', '~> 1.25', :platforms => [:jruby, :ruby_18]
|
10
|
+
gem 'minitest', '>= 5.0.5'
|
11
|
+
gem 'minitest-rspec_mocks'
|
12
|
+
gem 'rest-client', '~> 1.6.0', :platforms => [:jruby, :ruby_18]
|
13
|
+
gem 'simplecov'
|
14
|
+
gem 'sinatra', '~> 1.3'
|
15
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Ben Maraney
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# FaradayConnectionPool
|
2
|
+
|
3
|
+
FaradayConnectionPool provides a persistent Net::HTTP Faraday adapter.
|
4
|
+
Unlike Net::HTTP::Persistent, which has a connection-per-thread, connections are pooled across all threads and you will always get the most recently used connection. This should mean that you are more likely to get an existing connection with a reduced chance of getting a connection reset
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'faraday_connection_pool'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install faraday_connection_pool
|
18
|
+
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
1. If necessary `require 'faraday_connection_pool'`
|
23
|
+
|
24
|
+
2. Configure FaradayConnectionPool:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
FaradayConnectionPool.configure do |config|
|
28
|
+
config.size = 5 #The number of connections to held in the pool. There is a separate pool for each host/port.
|
29
|
+
config.pool_timeout = 5 #If no connection is available from the pool within :pool_timeout seconds the adapter will raise a Timeout::Error.
|
30
|
+
config.keep_alive_timeout = 30 #Connections which has been unused for :keep_alive_timeout seconds are not reused.
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
3. Configure your Faraday connections to use the `:net_http_pooled` adapter provided by the gem:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
Faraday.new(:url => 'http://klarna.com') do |conn|
|
38
|
+
conn.adapter :net_http_pooled
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
## Warning - Retries
|
43
|
+
|
44
|
+
FaradayConnectionPool will not automatically try and repair broken connections, so you should configure Faraday to retry
|
45
|
+
for you:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
Faraday.new do |conn|
|
49
|
+
conn.request :retry, max: 2, interval: 0.05,
|
50
|
+
interval_randomness: 0.5, backoff_factor: 2
|
51
|
+
exceptions: [ Faraday::Error::ConnectionFailed ]
|
52
|
+
conn.adapter :net_http_pooled
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
## Warning - Proxy Support
|
57
|
+
|
58
|
+
The `:net_http_pooled adapter` will not complain if you configure it to use a proxy server, but this code is entirely
|
59
|
+
untested. Use this at your own risk and file an issue to tell us how it goes.
|
60
|
+
|
61
|
+
## Tests
|
62
|
+
|
63
|
+
Run tests with `script/test`.
|
64
|
+
The test framework pulls in files from Faraday to save us setting up an integration test framework here.
|
65
|
+
|
66
|
+
## Contributing
|
67
|
+
|
68
|
+
1. Fork it ( `http://github.com/Ben-M/faraday_connection_pool/fork` )
|
69
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
70
|
+
3. Write your tests and code. Run `script/test` to check that the tests are passing.
|
71
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
72
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
73
|
+
5. Create new Pull Request
|
74
|
+
|
75
|
+
## Todo
|
76
|
+
* [ ] Make Faraday::Error::ConnectionFailed less general, so we can retry only Errno::ECONNRESET
|
77
|
+
* [ ] Allow host/port specific configuration
|
78
|
+
* [ ] Test proxy support
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'faraday_connection_pool/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "faraday_connection_pool"
|
8
|
+
spec.version = FaradayConnectionPool::VERSION
|
9
|
+
spec.authors = ["Ben Maraney"]
|
10
|
+
spec.email = ["ben@maraney.com"]
|
11
|
+
spec.summary = "A persistent Net::Http adapter for Faraday with a connection pool shared across threads and fibres."
|
12
|
+
spec.homepage = "https://github.com/Ben-M/faraday_connection_pool"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
|
23
|
+
spec.add_dependency "faraday", ">= 0.9.1"
|
24
|
+
spec.add_dependency "connection_pool", "~> 2.1"
|
25
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
require 'connection_pool'
|
3
|
+
|
4
|
+
module FaradayConnectionPool
|
5
|
+
|
6
|
+
class Configuration
|
7
|
+
attr_writer :size
|
8
|
+
attr_writer :pool_timeout
|
9
|
+
attr_writer :keep_alive_timeout
|
10
|
+
|
11
|
+
def size
|
12
|
+
@size ||= 5
|
13
|
+
end
|
14
|
+
|
15
|
+
def pool_timeout
|
16
|
+
@pool_timeout ||= 5
|
17
|
+
end
|
18
|
+
|
19
|
+
def keep_alive_timeout
|
20
|
+
@keep_alive_timeout ||= 30
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.configure
|
26
|
+
yield configuration if block_given?
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.configuration
|
30
|
+
@configuration ||= FaradayConnectionPool::Configuration.new
|
31
|
+
end
|
32
|
+
|
33
|
+
class Adapter
|
34
|
+
class NetHttpPooled < Faraday::Adapter::NetHttp
|
35
|
+
extend MonitorMixin
|
36
|
+
@@connection_pools = {}
|
37
|
+
|
38
|
+
def call(env)
|
39
|
+
env[:request_headers] ||= {}
|
40
|
+
env[:request_headers]['Connection'] = 'Keep-Alive' unless env[:request_headers]['Connection']
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
def with_net_http_connection(env)
|
45
|
+
connection_pool_for(env).with do |connection|
|
46
|
+
yield connection
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.purge_connection_pools
|
51
|
+
synchronize do
|
52
|
+
@@connection_pools = {}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def connection_pool_for(env)
|
58
|
+
self.class.synchronize do
|
59
|
+
keep_alive_timeout = FaradayConnectionPool.configuration.keep_alive_timeout
|
60
|
+
@@connection_pools[pool_key(env)] ||=
|
61
|
+
ConnectionPool.new(:size => FaradayConnectionPool.configuration.size,
|
62
|
+
:timeout => FaradayConnectionPool.configuration.pool_timeout) do
|
63
|
+
net_http_connection(env).tap do |connection|
|
64
|
+
connection.keep_alive_timeout = keep_alive_timeout
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def pool_key(env)
|
71
|
+
"#{env[:url].host}:#{env[:url].port}:#{proxy_identifier(env)}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def proxy_identifier(env)
|
75
|
+
env[:request][:proxy] ? "#{env[:request][:proxy][:uri]}" : ""
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
Faraday::Adapter.register_middleware :net_http_pooled => FaradayConnectionPool::Adapter::NetHttpPooled
|
data/script/proxy-server
ADDED
data/script/server
ADDED
data/script/test
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
faraday_gem_location = Gem.loaded_specs['faraday'].gem_dir
|
2
|
+
integration_location = File.join(faraday_gem_location, 'test', 'adapters', 'integration')
|
3
|
+
require integration_location
|
4
|
+
require 'minitest/rspec_mocks'
|
5
|
+
require_relative('../../lib/faraday_connection_pool')
|
6
|
+
|
7
|
+
module Adapters
|
8
|
+
class NetHttpPooledTest < Faraday::TestCase
|
9
|
+
include MiniTest::RSpecMocks
|
10
|
+
|
11
|
+
def adapter() :net_http_pooled end
|
12
|
+
|
13
|
+
behaviors = [:NonParallel]
|
14
|
+
behaviors << :Compression if RUBY_VERSION >= '1.9'
|
15
|
+
|
16
|
+
Integration.apply(self, *behaviors) do
|
17
|
+
|
18
|
+
def setup
|
19
|
+
FaradayConnectionPool::Adapter::NetHttpPooled.purge_connection_pools
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_connection_pool_receives_size_and_pool_timeout
|
23
|
+
test_size = 10
|
24
|
+
test_pool_timeout = 0.5
|
25
|
+
|
26
|
+
FaradayConnectionPool.configure do |config|
|
27
|
+
config.size = test_size
|
28
|
+
config.pool_timeout = test_pool_timeout
|
29
|
+
end
|
30
|
+
|
31
|
+
expect(ConnectionPool).to receive(:new).with(:size => test_size, :timeout => test_pool_timeout).and_call_original
|
32
|
+
|
33
|
+
create_connection.get '/echo'
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_connection_created_with_keep_alive_timeout
|
37
|
+
test_keep_alive_timeout = 18
|
38
|
+
FaradayConnectionPool.configure do |config|
|
39
|
+
config.keep_alive_timeout = test_keep_alive_timeout
|
40
|
+
end
|
41
|
+
|
42
|
+
expect_any_instance_of(Net::HTTP).to receive(:keep_alive_timeout=).with(test_keep_alive_timeout)
|
43
|
+
create_connection.get '/echo'
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_connection_from_pool_used
|
47
|
+
connection = double('connection')
|
48
|
+
pool = ConnectionPool.new { connection }
|
49
|
+
allow(ConnectionPool).to receive(:new).and_return(pool)
|
50
|
+
response = double('response', :code => 200, :body => :ok, :each_header => true)
|
51
|
+
|
52
|
+
expect(connection).to receive(:get).and_return(response)
|
53
|
+
|
54
|
+
assert_equal :ok, create_connection.get('/echo').body
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_connection_pools_reused
|
58
|
+
expect(ConnectionPool).to receive(:new).once.and_call_original
|
59
|
+
|
60
|
+
create_connection.get '/echo'
|
61
|
+
create_connection.get '/echo'
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_one_pool_per_host
|
65
|
+
expect(ConnectionPool).to receive(:new).twice.and_return(test_pool)
|
66
|
+
|
67
|
+
conn = create_connection
|
68
|
+
conn.host = 'hello'
|
69
|
+
conn.get '/echo'
|
70
|
+
|
71
|
+
conn.host = 'world'
|
72
|
+
conn.get '/echo'
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_one_pool_per_port
|
76
|
+
expect(ConnectionPool).to receive(:new).twice.and_return(test_pool)
|
77
|
+
|
78
|
+
conn = create_connection
|
79
|
+
conn.port = 1
|
80
|
+
conn.get '/echo'
|
81
|
+
|
82
|
+
conn.port = 2
|
83
|
+
conn.get '/echo'
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_keep_alive_header_set
|
87
|
+
response = create_connection.get('echo_header', :name => 'connection')
|
88
|
+
|
89
|
+
assert_equal('Keep-Alive', response.body)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_keep_alive_header_not_overwritten
|
93
|
+
response = create_connection.get('echo_header', :name => 'connection') do |request|
|
94
|
+
request.headers['Connection'] = 'close'
|
95
|
+
end
|
96
|
+
|
97
|
+
assert_equal('close', response.body)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def test_pool
|
102
|
+
connection = Net::HTTP.new(self.class.live_server.host, self.class.live_server.port)
|
103
|
+
pool = ConnectionPool.new { connection }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: faraday_connection_pool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Maraney
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faraday
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.9.1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: connection_pool
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.1'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.1'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- ben@maraney.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- CHANGELOG.md
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- faraday_connection_pool.gemspec
|
83
|
+
- lib/faraday_connection_pool.rb
|
84
|
+
- lib/faraday_connection_pool/version.rb
|
85
|
+
- script/proxy-server
|
86
|
+
- script/server
|
87
|
+
- script/test
|
88
|
+
- test/adapters/net_http_pooled_test.rb
|
89
|
+
homepage: https://github.com/Ben-M/faraday_connection_pool
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.2.2
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: A persistent Net::Http adapter for Faraday with a connection pool shared
|
113
|
+
across threads and fibres.
|
114
|
+
test_files:
|
115
|
+
- test/adapters/net_http_pooled_test.rb
|