connection_pool 2.1.3 → 2.2.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 +4 -4
- data/Changes.md +10 -0
- data/README.md +5 -0
- data/lib/connection_pool.rb +24 -13
- data/lib/connection_pool/timed_stack.rb +0 -22
- data/lib/connection_pool/version.rb +1 -1
- data/test/test_connection_pool.rb +41 -21
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57159a2ea25da28e141dc80936a642134fbc9680
|
4
|
+
data.tar.gz: 7f534538909e40c117b84090a89b6f4fcd5ca8ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb15e188af8037b01d59ab3728ee010033ab6c71cdd82ed6a8f4f59609c23791d9afdb8a9e31c755079cd1ce7c6e0ca20a7b43d2bd4b142b7ddacbd9b9ad94c3
|
7
|
+
data.tar.gz: 69e22e8e329f525fb875c2abe1090a35a63d035bb9337d9bd79604f46f1f1c3dbb92a83d6bf8d899388e8873cf04060c288bfef0e760e14b23a2fa12b1ffdf32
|
data/Changes.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
connection\_pool changelog
|
2
|
+
---------------------------
|
3
|
+
|
4
|
+
2.2.0
|
5
|
+
------
|
6
|
+
|
7
|
+
- Rollback `Timeout` handling introduced in 2.1.1 and 2.1.2. It seems
|
8
|
+
impossible to safely work around the issue. Please never, ever use
|
9
|
+
`Timeout.timeout` in your code or you will see rare but mysterious bugs. [#75]
|
10
|
+
|
1
11
|
2.1.3
|
2
12
|
------
|
3
13
|
|
data/README.md
CHANGED
@@ -8,6 +8,11 @@ MongoDB has its own connection pool. ActiveRecord has its own connection pool.
|
|
8
8
|
This is a generic connection pool that can be used with anything, e.g. Redis,
|
9
9
|
Dalli and other Ruby network clients.
|
10
10
|
|
11
|
+
**WARNING**: Don't ever use `Timeout.timeout` in your Ruby code or you will see
|
12
|
+
occasional silent corruption and mysterious errors. The Timeout API is unsafe
|
13
|
+
and cannot be used correctly, ever. Use proper socket timeout options as
|
14
|
+
exposed by Net::HTTP, Redis, Dalli, etc.
|
15
|
+
|
11
16
|
|
12
17
|
Usage
|
13
18
|
-----
|
data/lib/connection_pool.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'connection_pool/version'
|
2
2
|
require_relative 'connection_pool/timed_stack'
|
3
3
|
|
4
|
+
|
4
5
|
# Generic connection pool class for e.g. sharing a limited number of network connections
|
5
6
|
# among many threads. Note: Connections are lazily created.
|
6
7
|
#
|
@@ -52,26 +53,36 @@ class ConnectionPool
|
|
52
53
|
@key = :"current-#{@available.object_id}"
|
53
54
|
end
|
54
55
|
|
56
|
+
if Thread.respond_to?(:handle_interrupt)
|
57
|
+
|
58
|
+
# MRI
|
59
|
+
def with(options = {})
|
60
|
+
Thread.handle_interrupt(Exception => :never) do
|
61
|
+
conn = checkout(options)
|
62
|
+
begin
|
63
|
+
Thread.handle_interrupt(Exception => :immediate) do
|
64
|
+
yield conn
|
65
|
+
end
|
66
|
+
ensure
|
67
|
+
checkin
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
else
|
73
|
+
|
74
|
+
# jruby 1.7.x
|
55
75
|
def with(options = {})
|
56
|
-
# Connections can become corrupted via Timeout::Error. Discard
|
57
|
-
# any connection whose usage after checkout does not finish as expected.
|
58
|
-
# See #67
|
59
|
-
success = false
|
60
76
|
conn = checkout(options)
|
61
77
|
begin
|
62
|
-
|
63
|
-
success = true # means the connection wasn't interrupted
|
64
|
-
result
|
78
|
+
yield conn
|
65
79
|
ensure
|
66
|
-
|
67
|
-
# everything is roses, we can safely check the connection back in
|
68
|
-
checkin
|
69
|
-
else
|
70
|
-
@available.discard!(pop_connection)
|
71
|
-
end
|
80
|
+
checkin
|
72
81
|
end
|
73
82
|
end
|
74
83
|
|
84
|
+
end
|
85
|
+
|
75
86
|
def checkout(options = {})
|
76
87
|
conn = if stack.empty?
|
77
88
|
timeout = options[:timeout] || @timeout
|
@@ -117,28 +117,6 @@ class ConnectionPool::TimedStack
|
|
117
117
|
@max - @created + @que.length
|
118
118
|
end
|
119
119
|
|
120
|
-
##
|
121
|
-
# Indicates that a connection isn't coming back, allowing a new one to be
|
122
|
-
# created to replace it.
|
123
|
-
|
124
|
-
def discard!(obj)
|
125
|
-
@mutex.synchronize do
|
126
|
-
if @shutdown_block
|
127
|
-
@shutdown_block.call(obj)
|
128
|
-
else
|
129
|
-
# try to shut down the connection before throwing it away
|
130
|
-
if obj.respond_to?(:close) # Dalli::Client
|
131
|
-
obj.close rescue nil
|
132
|
-
elsif obj.respond_to?(:disconnect!) # Redis
|
133
|
-
obj.disconnect! rescue nil
|
134
|
-
end
|
135
|
-
@created -= 1
|
136
|
-
end
|
137
|
-
|
138
|
-
@resource.broadcast
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
120
|
private
|
143
121
|
|
144
122
|
##
|
@@ -109,38 +109,58 @@ class TestConnectionPool < Minitest::Test
|
|
109
109
|
assert Thread.new { pool.checkout }.join
|
110
110
|
end
|
111
111
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
112
|
+
def test_with_timeout
|
113
|
+
pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
|
114
|
+
|
115
|
+
assert_raises Timeout::Error do
|
116
|
+
Timeout.timeout(0.01) do
|
117
|
+
pool.with do |obj|
|
118
|
+
assert_equal 0, pool.instance_variable_get(:@available).instance_variable_get(:@que).size
|
119
|
+
sleep 0.015
|
120
|
+
end
|
119
121
|
end
|
120
122
|
end
|
123
|
+
assert_equal 1, pool.instance_variable_get(:@available).instance_variable_get(:@que).size
|
124
|
+
end
|
121
125
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
# no "connections" allocated yet
|
126
|
-
assert_equal [], ObjectSpace.each_object(marker_class).to_a
|
126
|
+
def test_checkout_ignores_timeout
|
127
|
+
skip("Thread.handle_interrupt not available") unless Thread.respond_to?(:handle_interrupt)
|
127
128
|
|
128
|
-
|
129
|
+
pool = ConnectionPool.new(:timeout => 0, :size => 1) { Object.new }
|
130
|
+
def pool.checkout(options)
|
131
|
+
sleep 0.015
|
132
|
+
super
|
133
|
+
end
|
129
134
|
|
135
|
+
did_something = false
|
130
136
|
assert_raises Timeout::Error do
|
131
|
-
Timeout.timeout(
|
132
|
-
pool.with do
|
133
|
-
|
134
|
-
|
135
|
-
|
137
|
+
Timeout.timeout(0.01) do
|
138
|
+
pool.with do |obj|
|
139
|
+
did_something = true
|
140
|
+
# Timeout::Error will be triggered by any non-trivial Ruby code
|
141
|
+
# executed here since it couldn't be raised during checkout.
|
142
|
+
# It looks like setting the local variable above does not trigger
|
143
|
+
# the Timeout check in MRI 2.2.1.
|
144
|
+
obj.tap { obj.hash }
|
136
145
|
end
|
137
146
|
end
|
138
147
|
end
|
148
|
+
assert did_something
|
149
|
+
assert_equal 1, pool.instance_variable_get(:@available).instance_variable_get(:@que).size
|
150
|
+
end
|
139
151
|
|
140
|
-
|
152
|
+
def test_explicit_return
|
153
|
+
pool = ConnectionPool.new(:timeout => 0, :size => 1) do
|
154
|
+
mock = Minitest::Mock.new
|
155
|
+
def mock.disconnect!
|
156
|
+
raise "should not disconnect upon explicit return"
|
157
|
+
end
|
158
|
+
mock
|
159
|
+
end
|
141
160
|
|
142
|
-
|
143
|
-
|
161
|
+
pool.with do |conn|
|
162
|
+
return true
|
163
|
+
end
|
144
164
|
end
|
145
165
|
|
146
166
|
def test_with_timeout_override
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: connection_pool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Perham
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-04-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|