connection_pool 2.2.2 → 2.2.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
- SHA1:
3
- metadata.gz: cf8177bf07f6c8e68b13f28416f6ccc0c64803af
4
- data.tar.gz: ff9c836ce5576d4d0cb1edf8d858a761f982e437
2
+ SHA256:
3
+ metadata.gz: e9fefa40cd9db0f5add54482a9f980d808b5bb578e83a5a8bf287c636c41704d
4
+ data.tar.gz: ec25d36c42cfb863e768bf49b18316d955397edaa8862f92d27687ab2a089bf0
5
5
  SHA512:
6
- metadata.gz: 73bda4d8d0b3cc9daef5c93bb98b7649d811bd5c8f467e25c3aaf7d3353541225e7b30e1efd481a14e45f5c56b5fc846d49dabdd9a167702a71c4a9631a9b6a2
7
- data.tar.gz: a331275f67b3635e09792e646113e32bdc74254a2cdff032e972c6f2ebedd6391a1e508c36be7c4e33b40e2a07efe029a2ad0267c3ba4dc20b22813df86427bb
6
+ metadata.gz: d8653437078b6334be998d16f4851e12a21e8caca8338a07559c9bfbe646dc6023a7370aad6e33be905b05d6eaab8f249387eaa72b16a478f57c9c497adbbf30
7
+ data.tar.gz: 2a437d085a3f11376338ee32debe5e7ff38fc28fdc8d0d318287c2890bc90ce2d282468981dde43c8391798d113e1391d7998a5f5e571f1021ae99dfff6893e2
@@ -1,10 +1,12 @@
1
1
  ---
2
- sudo: false
3
2
  cache: bundler
4
3
  language: ruby
5
4
  rvm:
6
- - 2.2.9
7
- - 2.3.6
8
- - 2.4.3
9
- - 2.5.0
5
+ - 2.3
6
+ - 2.4
7
+ - 2.5
8
+ - 2.6
9
+ - 2.7
10
10
  - jruby
11
+ jdk:
12
+ - openjdk11
data/Changes.md CHANGED
@@ -1,5 +1,12 @@
1
- connection\_pool changelog
2
- ---------------------------
1
+ # connection_pool Changelog
2
+
3
+ 2.2.3
4
+ ------
5
+
6
+ - Pool now throws `ConnectionPool::TimeoutError` on timeout. [#130]
7
+ - Use monotonic clock present in all modern Rubies [Tero Tasanen, #109]
8
+ - Remove code hacks necessary for JRuby 1.7
9
+ - Expose wrapped pool from ConnectionPool::Wrapper [Thomas Lecavelier, #113]
3
10
 
4
11
  2.2.2
5
12
  ------
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec(development_group: :runtime)
4
+
5
+ gem "standard"
data/README.md CHANGED
@@ -51,7 +51,7 @@ You can use `ConnectionPool::Wrapper` to wrap a single global connection,
51
51
  making it easier to migrate existing connection code over time:
52
52
 
53
53
  ``` ruby
54
- $redis = ConnectionPool::Wrapper.new(size: 5, timeout: 3) { Redis.connect }
54
+ $redis = ConnectionPool::Wrapper.new(size: 5, timeout: 3) { Redis.new }
55
55
  $redis.sadd('foo', 1)
56
56
  $redis.smembers('foo')
57
57
  ```
@@ -87,6 +87,20 @@ Shutting down a connection pool will block until all connections are checked in
87
87
  **Note that shutting down is completely optional**; Ruby's garbage collector will reclaim
88
88
  unreferenced pools under normal circumstances.
89
89
 
90
+ ## Current State
91
+
92
+ There are several methods that return information about a pool.
93
+
94
+ ```ruby
95
+ cp = ConnectionPool.new(size: 10) { Redis.new }
96
+ cp.size # => 10
97
+ cp.available # => 10
98
+
99
+ cp.with do |conn|
100
+ cp.size # => 10
101
+ cp.available # => 9
102
+ end
103
+ ```
90
104
 
91
105
  Notes
92
106
  -----
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
- require 'bundler/gem_tasks'
1
+ require "bundler/gem_tasks"
2
2
 
3
- require 'rake/testtask'
3
+ require "rake/testtask"
4
+ require "standard/rake"
4
5
  Rake::TestTask.new
5
6
 
6
- task :default => :test
7
+ task default: :test
@@ -1,21 +1,20 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require "./lib/connection_pool/version"
3
2
 
4
3
  Gem::Specification.new do |s|
5
- s.name = "connection_pool"
6
- s.version = ConnectionPool::VERSION
7
- s.platform = Gem::Platform::RUBY
8
- s.authors = ["Mike Perham", "Damian Janowski"]
9
- s.email = ["mperham@gmail.com", "damian@educabilia.com"]
10
- s.homepage = "https://github.com/mperham/connection_pool"
11
- s.description = s.summary = %q{Generic connection pool for Ruby}
4
+ s.name = "connection_pool"
5
+ s.version = ConnectionPool::VERSION
6
+ s.platform = Gem::Platform::RUBY
7
+ s.authors = ["Mike Perham", "Damian Janowski"]
8
+ s.email = ["mperham@gmail.com", "damian@educabilia.com"]
9
+ s.homepage = "https://github.com/mperham/connection_pool"
10
+ s.description = s.summary = "Generic connection pool for Ruby"
12
11
 
13
- s.files = `git ls-files`.split("\n")
14
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ s.files = `git ls-files`.split("\n")
13
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
16
15
  s.require_paths = ["lib"]
17
16
  s.license = "MIT"
18
- s.add_development_dependency 'bundler'
19
- s.add_development_dependency 'minitest', '>= 5.0.0'
20
- s.add_development_dependency 'rake'
17
+ s.add_development_dependency "bundler"
18
+ s.add_development_dependency "minitest", ">= 5.0.0"
19
+ s.add_development_dependency "rake"
21
20
  end
@@ -1,14 +1,18 @@
1
- require_relative 'connection_pool/version'
2
- require_relative 'connection_pool/timed_stack'
1
+ require "timeout"
2
+ require "connection_pool/version"
3
3
 
4
+ class ConnectionPool
5
+ class Error < ::RuntimeError; end
6
+ class PoolShuttingDownError < ::ConnectionPool::Error; end
7
+ class TimeoutError < ::Timeout::Error; end
8
+ end
4
9
 
5
- # Generic connection pool class for e.g. sharing a limited number of network connections
6
- # among many threads. Note: Connections are lazily created.
10
+ # Generic connection pool class for sharing a limited number of objects or network connections
11
+ # among many threads. Note: pool elements are lazily created.
7
12
  #
8
13
  # Example usage with block (faster):
9
14
  #
10
15
  # @pool = ConnectionPool.new { Redis.new }
11
- #
12
16
  # @pool.with do |redis|
13
17
  # redis.lpop('my-list') if redis.llen('my-list') > 0
14
18
  # end
@@ -34,29 +38,23 @@ require_relative 'connection_pool/timed_stack'
34
38
  class ConnectionPool
35
39
  DEFAULTS = {size: 5, timeout: 5}
36
40
 
37
- class Error < RuntimeError
38
- end
39
-
40
41
  def self.wrap(options, &block)
41
42
  Wrapper.new(options, &block)
42
43
  end
43
44
 
44
45
  def initialize(options = {}, &block)
45
- raise ArgumentError, 'Connection pool requires a block' unless block
46
+ raise ArgumentError, "Connection pool requires a block" unless block
46
47
 
47
48
  options = DEFAULTS.merge(options)
48
49
 
49
- @size = options.fetch(:size)
50
+ @size = Integer(options.fetch(:size))
50
51
  @timeout = options.fetch(:timeout)
51
52
 
52
53
  @available = TimedStack.new(@size, &block)
53
- @key = :"current-#{@available.object_id}"
54
- @key_count = :"current-#{@available.object_id}-count"
54
+ @key = :"pool-#{@available.object_id}"
55
+ @key_count = :"pool-#{@available.object_id}-count"
55
56
  end
56
57
 
57
- if Thread.respond_to?(:handle_interrupt)
58
-
59
- # MRI
60
58
  def with(options = {})
61
59
  Thread.handle_interrupt(Exception => :never) do
62
60
  conn = checkout(options)
@@ -70,27 +68,13 @@ if Thread.respond_to?(:handle_interrupt)
70
68
  end
71
69
  end
72
70
 
73
- else
74
-
75
- # jruby 1.7.x
76
- def with(options = {})
77
- conn = checkout(options)
78
- begin
79
- yield conn
80
- ensure
81
- checkin
82
- end
83
- end
84
-
85
- end
86
-
87
71
  def checkout(options = {})
88
72
  if ::Thread.current[@key]
89
- ::Thread.current[@key_count]+= 1
73
+ ::Thread.current[@key_count] += 1
90
74
  ::Thread.current[@key]
91
75
  else
92
- ::Thread.current[@key_count]= 1
93
- ::Thread.current[@key]= @available.pop(options[:timeout] || @timeout)
76
+ ::Thread.current[@key_count] = 1
77
+ ::Thread.current[@key] = @available.pop(options[:timeout] || @timeout)
94
78
  end
95
79
  end
96
80
 
@@ -98,12 +82,12 @@ end
98
82
  if ::Thread.current[@key]
99
83
  if ::Thread.current[@key_count] == 1
100
84
  @available.push(::Thread.current[@key])
101
- ::Thread.current[@key]= nil
85
+ ::Thread.current[@key] = nil
102
86
  else
103
- ::Thread.current[@key_count]-= 1
87
+ ::Thread.current[@key_count] -= 1
104
88
  end
105
89
  else
106
- raise ConnectionPool::Error, 'no connections are checked out'
90
+ raise ConnectionPool::Error, "no connections are checked out"
107
91
  end
108
92
 
109
93
  nil
@@ -114,48 +98,13 @@ end
114
98
  end
115
99
 
116
100
  # Size of this connection pool
117
- def size
118
- @size
119
- end
101
+ attr_reader :size
120
102
 
121
103
  # Number of pool entries available for checkout at this instant.
122
104
  def available
123
105
  @available.length
124
106
  end
125
-
126
- private
127
-
128
- class Wrapper < ::BasicObject
129
- METHODS = [:with, :pool_shutdown]
130
-
131
- def initialize(options = {}, &block)
132
- @pool = options.fetch(:pool) { ::ConnectionPool.new(options, &block) }
133
- end
134
-
135
- def with(&block)
136
- @pool.with(&block)
137
- end
138
-
139
- def pool_shutdown(&block)
140
- @pool.shutdown(&block)
141
- end
142
-
143
- def pool_size
144
- @pool.size
145
- end
146
-
147
- def pool_available
148
- @pool.available
149
- end
150
-
151
- def respond_to?(id, *args)
152
- METHODS.include?(id) || with { |c| c.respond_to?(id, *args) }
153
- end
154
-
155
- def method_missing(name, *args, &block)
156
- with do |connection|
157
- connection.send(name, *args, &block)
158
- end
159
- end
160
- end
161
107
  end
108
+
109
+ require "connection_pool/timed_stack"
110
+ require "connection_pool/wrapper"
@@ -1,13 +1,3 @@
1
- require 'thread'
2
- require 'timeout'
3
- require_relative 'monotonic_time'
4
-
5
- ##
6
- # Raised when you attempt to retrieve a connection from a pool that has been
7
- # shut down.
8
-
9
- class ConnectionPool::PoolShuttingDownError < RuntimeError; end
10
-
11
1
  ##
12
2
  # The TimedStack manages a pool of homogeneous connections (or any resource
13
3
  # you wish to manage). Connections are created lazily up to a given maximum
@@ -59,7 +49,7 @@ class ConnectionPool::TimedStack
59
49
  @resource.broadcast
60
50
  end
61
51
  end
62
- alias_method :<<, :push
52
+ alias << push
63
53
 
64
54
  ##
65
55
  # Retrieves a connection from the stack. If a connection is available it is
@@ -74,7 +64,7 @@ class ConnectionPool::TimedStack
74
64
  options, timeout = timeout, 0.5 if Hash === timeout
75
65
  timeout = options.fetch :timeout, timeout
76
66
 
77
- deadline = ConnectionPool.monotonic_time + timeout
67
+ deadline = current_time + timeout
78
68
  @mutex.synchronize do
79
69
  loop do
80
70
  raise ConnectionPool::PoolShuttingDownError if @shutdown_block
@@ -83,8 +73,8 @@ class ConnectionPool::TimedStack
83
73
  connection = try_create(options)
84
74
  return connection if connection
85
75
 
86
- to_wait = deadline - ConnectionPool.monotonic_time
87
- raise Timeout::Error, "Waited #{timeout} sec" if to_wait <= 0
76
+ to_wait = deadline - current_time
77
+ raise ConnectionPool::TimeoutError, "Waited #{timeout} sec" if to_wait <= 0
88
78
  @resource.wait(@mutex, to_wait)
89
79
  end
90
80
  end
@@ -121,6 +111,10 @@ class ConnectionPool::TimedStack
121
111
 
122
112
  private
123
113
 
114
+ def current_time
115
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
116
+ end
117
+
124
118
  ##
125
119
  # This is an extension point for TimedStack and is called with a mutex.
126
120
  #
@@ -1,3 +1,3 @@
1
1
  class ConnectionPool
2
- VERSION = "2.2.2"
2
+ VERSION = "2.2.3"
3
3
  end
@@ -0,0 +1,43 @@
1
+ class ConnectionPool
2
+ class Wrapper < ::BasicObject
3
+ METHODS = [:with, :pool_shutdown, :wrapped_pool]
4
+
5
+ def initialize(options = {}, &block)
6
+ @pool = options.fetch(:pool) { ::ConnectionPool.new(options, &block) }
7
+ end
8
+
9
+ def wrapped_pool
10
+ @pool
11
+ end
12
+
13
+ def with(&block)
14
+ @pool.with(&block)
15
+ end
16
+
17
+ def pool_shutdown(&block)
18
+ @pool.shutdown(&block)
19
+ end
20
+
21
+ def pool_size
22
+ @pool.size
23
+ end
24
+
25
+ def pool_available
26
+ @pool.available
27
+ end
28
+
29
+ def respond_to?(id, *args)
30
+ METHODS.include?(id) || with { |c| c.respond_to?(id, *args) }
31
+ end
32
+
33
+ # rubocop:disable Style/MethodMissingSuper
34
+ # rubocop:disable Style/MissingRespondToMissing
35
+ def method_missing(name, *args, &block)
36
+ with do |connection|
37
+ connection.send(name, *args, &block)
38
+ end
39
+ end
40
+ # rubocop:enable Style/MethodMissingSuper
41
+ # rubocop:enable Style/MissingRespondToMissing
42
+ end
43
+ end
@@ -1,8 +1,8 @@
1
- gem 'minitest'
1
+ gem "minitest"
2
2
 
3
- require 'minitest/pride'
4
- require 'minitest/autorun'
3
+ require "minitest/pride"
4
+ require "minitest/autorun"
5
5
 
6
6
  $VERBOSE = 1
7
7
 
8
- require_relative '../lib/connection_pool'
8
+ require_relative "../lib/connection_pool"
@@ -1,7 +1,6 @@
1
- require_relative 'helper'
1
+ require_relative "helper"
2
2
 
3
3
  class TestConnectionPool < Minitest::Test
4
-
5
4
  class NetworkConnection
6
5
  SLEEP_TIME = 0.1
7
6
 
@@ -43,12 +42,12 @@ class TestConnectionPool < Minitest::Test
43
42
  end
44
43
 
45
44
  def use_pool(pool, size)
46
- Array.new(size) do
45
+ Array.new(size) {
47
46
  Thread.new do
48
- pool.with do sleep end
47
+ pool.with { sleep }
49
48
  end
50
- end.each do |thread|
51
- Thread.pass until thread.status == 'sleep'
49
+ }.each do |thread|
50
+ Thread.pass until thread.status == "sleep"
52
51
  end
53
52
  end
54
53
 
@@ -67,13 +66,13 @@ class TestConnectionPool < Minitest::Test
67
66
 
68
67
  generations = 3
69
68
 
70
- result = Array.new(pool_size * generations) do
69
+ result = Array.new(pool_size * generations) {
71
70
  Thread.new do
72
71
  pool.with do |net|
73
72
  net.do_something
74
73
  end
75
74
  end
76
- end.map(&:value)
75
+ }.map(&:value)
77
76
 
78
77
  finish = Time.new
79
78
 
@@ -84,14 +83,14 @@ class TestConnectionPool < Minitest::Test
84
83
 
85
84
  def test_timeout
86
85
  pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
87
- thread = Thread.new do
86
+ thread = Thread.new {
88
87
  pool.with do |net|
89
88
  net.do_something
90
89
  sleep 0.01
91
90
  end
92
- end
91
+ }
93
92
 
94
- Thread.pass while thread.status == 'run'
93
+ Thread.pass while thread.status == "run"
95
94
 
96
95
  assert_raises Timeout::Error do
97
96
  pool.with { |net| net.do_something }
@@ -108,9 +107,11 @@ class TestConnectionPool < Minitest::Test
108
107
  pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
109
108
 
110
109
  pool.with do
111
- assert_raises Timeout::Error do
112
- Thread.new { pool.checkout }.join
113
- end
110
+ Thread.new {
111
+ assert_raises Timeout::Error do
112
+ pool.checkout
113
+ end
114
+ }.join
114
115
  end
115
116
 
116
117
  assert Thread.new { pool.checkout }.join
@@ -122,17 +123,24 @@ class TestConnectionPool < Minitest::Test
122
123
  assert_raises Timeout::Error do
123
124
  Timeout.timeout(0.01) do
124
125
  pool.with do |obj|
125
- assert_equal 0, pool.instance_variable_get(:@available).instance_variable_get(:@que).size
126
+ assert_equal 0, pool.available
126
127
  sleep 0.015
127
128
  end
128
129
  end
129
130
  end
130
- assert_equal 1, pool.instance_variable_get(:@available).instance_variable_get(:@que).size
131
+ assert_equal 1, pool.available
131
132
  end
132
133
 
133
- def test_checkout_ignores_timeout
134
- skip("Thread.handle_interrupt not available") unless Thread.respond_to?(:handle_interrupt)
134
+ def test_invalid_size
135
+ assert_raises ArgumentError, TypeError do
136
+ ConnectionPool.new(timeout: 0, size: nil) { Object.new }
137
+ end
138
+ assert_raises ArgumentError, TypeError do
139
+ ConnectionPool.new(timeout: 0, size: "") { Object.new }
140
+ end
141
+ end
135
142
 
143
+ def test_handle_interrupt_ensures_checkin
136
144
  pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
137
145
  def pool.checkout(options)
138
146
  sleep 0.015
@@ -140,7 +148,8 @@ class TestConnectionPool < Minitest::Test
140
148
  end
141
149
 
142
150
  did_something = false
143
- assert_raises Timeout::Error do
151
+
152
+ action = lambda do
144
153
  Timeout.timeout(0.01) do
145
154
  pool.with do |obj|
146
155
  did_something = true
@@ -152,18 +161,33 @@ class TestConnectionPool < Minitest::Test
152
161
  end
153
162
  end
154
163
  end
155
- assert did_something
156
- assert_equal 1, pool.instance_variable_get(:@available).instance_variable_get(:@que).size
164
+
165
+ if RUBY_ENGINE == "ruby"
166
+ # These asserts rely on the Ruby implementation reaching `did_something =
167
+ # true` before the interrupt is detected by the thread. Interrupt
168
+ # detection timing is implementation-specific in practice, with JRuby,
169
+ # Rubinius, and TruffleRuby all having different interrupt timings to MRI.
170
+ # In fact they generally detect interrupts more quickly than MRI, so they
171
+ # may not reach `did_something = true` before detecting the interrupt.
172
+
173
+ assert_raises Timeout::Error, &action
174
+
175
+ assert did_something
176
+ else
177
+ action.call
178
+ end
179
+
180
+ assert_equal 1, pool.available
157
181
  end
158
182
 
159
183
  def test_explicit_return
160
- pool = ConnectionPool.new(timeout: 0, size: 1) do
184
+ pool = ConnectionPool.new(timeout: 0, size: 1) {
161
185
  mock = Minitest::Mock.new
162
186
  def mock.disconnect!
163
187
  raise "should not disconnect upon explicit return"
164
188
  end
165
189
  mock
166
- end
190
+ }
167
191
 
168
192
  pool.with do |conn|
169
193
  return true
@@ -173,14 +197,14 @@ class TestConnectionPool < Minitest::Test
173
197
  def test_with_timeout_override
174
198
  pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
175
199
 
176
- t = Thread.new do
200
+ t = Thread.new {
177
201
  pool.with do |net|
178
202
  net.do_something
179
203
  sleep 0.01
180
204
  end
181
- end
205
+ }
182
206
 
183
- Thread.pass while t.status == 'run'
207
+ Thread.pass while t.status == "run"
184
208
 
185
209
  assert_raises Timeout::Error do
186
210
  pool.with { |net| net.do_something }
@@ -195,9 +219,11 @@ class TestConnectionPool < Minitest::Test
195
219
  pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
196
220
  conn = pool.checkout
197
221
 
198
- assert_raises Timeout::Error do
199
- Thread.new { pool.checkout }.join
200
- end
222
+ Thread.new {
223
+ assert_raises Timeout::Error do
224
+ pool.checkout
225
+ end
226
+ }.join
201
227
 
202
228
  pool.checkin
203
229
 
@@ -206,17 +232,14 @@ class TestConnectionPool < Minitest::Test
206
232
 
207
233
  def test_returns_value
208
234
  pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
209
- assert_equal 1, pool.with {|o| 1 }
235
+ assert_equal 1, pool.with { |o| 1 }
210
236
  end
211
237
 
212
238
  def test_checkin_never_checkout
213
239
  pool = ConnectionPool.new(timeout: 0, size: 1) { Object.new }
214
240
 
215
- e = assert_raises ConnectionPool::Error do
216
- pool.checkin
217
- end
218
-
219
- assert_equal 'no connections are checked out', e.message
241
+ e = assert_raises(ConnectionPool::Error) { pool.checkin }
242
+ assert_equal "no connections are checked out", e.message
220
243
  end
221
244
 
222
245
  def test_checkin_no_current_checkout
@@ -238,11 +261,11 @@ class TestConnectionPool < Minitest::Test
238
261
 
239
262
  pool.checkin
240
263
 
241
- assert_raises Timeout::Error do
242
- Thread.new do
264
+ Thread.new {
265
+ assert_raises Timeout::Error do
243
266
  pool.checkout
244
- end.join
245
- end
267
+ end
268
+ }.join
246
269
 
247
270
  pool.checkin
248
271
 
@@ -263,9 +286,9 @@ class TestConnectionPool < Minitest::Test
263
286
  pool = ConnectionPool.new(size: 2) { NetworkConnection.new }
264
287
  conn = pool.checkout
265
288
 
266
- t = Thread.new do
289
+ t = Thread.new {
267
290
  pool.checkout
268
- end
291
+ }
269
292
 
270
293
  refute_same conn, t.value
271
294
  end
@@ -281,14 +304,14 @@ class TestConnectionPool < Minitest::Test
281
304
  def test_checkout_timeout_override
282
305
  pool = ConnectionPool.new(timeout: 0, size: 1) { NetworkConnection.new }
283
306
 
284
- thread = Thread.new do
307
+ thread = Thread.new {
285
308
  pool.with do |net|
286
309
  net.do_something
287
310
  sleep 0.01
288
311
  end
289
- end
312
+ }
290
313
 
291
- Thread.pass while thread.status == 'run'
314
+ Thread.pass while thread.status == "run"
292
315
 
293
316
  assert_raises Timeout::Error do
294
317
  pool.checkout
@@ -315,22 +338,22 @@ class TestConnectionPool < Minitest::Test
315
338
 
316
339
  def test_return_value
317
340
  pool = ConnectionPool.new(timeout: 2 * NetworkConnection::SLEEP_TIME, size: 1) { NetworkConnection.new }
318
- result = pool.with do |net|
341
+ result = pool.with { |net|
319
342
  net.fast
320
- end
343
+ }
321
344
  assert_equal 1, result
322
345
  end
323
346
 
324
347
  def test_heavy_threading
325
348
  pool = ConnectionPool.new(timeout: 0.5, size: 3) { NetworkConnection.new }
326
349
 
327
- threads = Array.new(20) do
350
+ threads = Array.new(20) {
328
351
  Thread.new do
329
352
  pool.with do |net|
330
353
  sleep 0.01
331
354
  end
332
355
  end
333
- end
356
+ }
334
357
 
335
358
  threads.map { |thread| thread.join }
336
359
  end
@@ -338,9 +361,9 @@ class TestConnectionPool < Minitest::Test
338
361
  def test_reuses_objects_when_pool_not_saturated
339
362
  pool = ConnectionPool.new(size: 5) { NetworkConnection.new }
340
363
 
341
- ids = 10.times.map do
364
+ ids = 10.times.map {
342
365
  pool.with { |c| c.object_id }
343
- end
366
+ }
344
367
 
345
368
  assert_equal 1, ids.uniq.size
346
369
  end
@@ -349,32 +372,32 @@ class TestConnectionPool < Minitest::Test
349
372
  recorder = Recorder.new
350
373
  pool = ConnectionPool.new(size: 1) { recorder }
351
374
  pool.with do |r_outer|
352
- @other = Thread.new do |t|
375
+ @other = Thread.new { |t|
353
376
  pool.with do |r_other|
354
- r_other.do_work('other')
377
+ r_other.do_work("other")
355
378
  end
356
- end
379
+ }
357
380
 
358
381
  pool.with do |r_inner|
359
- r_inner.do_work('inner')
382
+ r_inner.do_work("inner")
360
383
  end
361
384
 
362
385
  Thread.pass
363
386
 
364
- r_outer.do_work('outer')
387
+ r_outer.do_work("outer")
365
388
  end
366
389
 
367
390
  @other.join
368
391
 
369
- assert_equal ['inner', 'outer', 'other'], recorder.calls
392
+ assert_equal ["inner", "outer", "other"], recorder.calls
370
393
  end
371
394
 
372
395
  def test_shutdown_is_executed_for_all_connections
373
396
  recorders = []
374
397
 
375
- pool = ConnectionPool.new(size: 3) do
398
+ pool = ConnectionPool.new(size: 3) {
376
399
  Recorder.new.tap { |r| recorders << r }
377
- end
400
+ }
378
401
 
379
402
  threads = use_pool pool, 3
380
403
 
@@ -390,7 +413,7 @@ class TestConnectionPool < Minitest::Test
390
413
  def test_raises_error_after_shutting_down
391
414
  pool = ConnectionPool.new(size: 1) { true }
392
415
 
393
- pool.shutdown { }
416
+ pool.shutdown {}
394
417
 
395
418
  assert_raises ConnectionPool::PoolShuttingDownError do
396
419
  pool.checkout
@@ -400,9 +423,9 @@ class TestConnectionPool < Minitest::Test
400
423
  def test_runs_shutdown_block_asynchronously_if_connection_was_in_use
401
424
  recorders = []
402
425
 
403
- pool = ConnectionPool.new(size: 3) do
426
+ pool = ConnectionPool.new(size: 3) {
404
427
  Recorder.new.tap { |r| recorders << r }
405
- end
428
+ }
406
429
 
407
430
  threads = use_pool pool, 2
408
431
 
@@ -422,7 +445,7 @@ class TestConnectionPool < Minitest::Test
422
445
  end
423
446
 
424
447
  def test_raises_an_error_if_shutdown_is_called_without_a_block
425
- pool = ConnectionPool.new(size: 1) { }
448
+ pool = ConnectionPool.new(size: 1) {}
426
449
 
427
450
  assert_raises ArgumentError do
428
451
  pool.shutdown
@@ -432,9 +455,9 @@ class TestConnectionPool < Minitest::Test
432
455
  def test_shutdown_is_executed_for_all_connections_in_wrapped_pool
433
456
  recorders = []
434
457
 
435
- wrapper = ConnectionPool::Wrapper.new(size: 3) do
458
+ wrapper = ConnectionPool::Wrapper.new(size: 3) {
436
459
  Recorder.new.tap { |r| recorders << r }
437
- end
460
+ }
438
461
 
439
462
  threads = use_pool wrapper, 3
440
463
 
@@ -447,6 +470,11 @@ class TestConnectionPool < Minitest::Test
447
470
  assert_equal [["shutdown"]] * 3, recorders.map { |r| r.calls }
448
471
  end
449
472
 
473
+ def test_wrapper_wrapped_pool
474
+ wrapper = ConnectionPool::Wrapper.new { NetworkConnection.new }
475
+ assert_equal ConnectionPool, wrapper.wrapped_pool.class
476
+ end
477
+
450
478
  def test_wrapper_method_missing
451
479
  wrapper = ConnectionPool::Wrapper.new { NetworkConnection.new }
452
480
 
@@ -466,14 +494,14 @@ class TestConnectionPool < Minitest::Test
466
494
  wrapper = ConnectionPool::Wrapper.new(timeout: 0, size: 1) { Object.new }
467
495
 
468
496
  wrapper.with do
469
- assert_raises Timeout::Error do
470
- Thread.new do
471
- wrapper.with { flunk 'connection checked out :(' }
472
- end.join
473
- end
497
+ Thread.new {
498
+ assert_raises Timeout::Error do
499
+ wrapper.with { flunk "connection checked out :(" }
500
+ end
501
+ }.join
474
502
  end
475
503
 
476
- assert Thread.new { wrapper.with { } }.join
504
+ assert Thread.new { wrapper.with {} }.join
477
505
  end
478
506
 
479
507
  class ConnWithEval
@@ -493,10 +521,10 @@ class TestConnectionPool < Minitest::Test
493
521
  pool = ConnectionPool.new(size: 1) { recorder }
494
522
  wrapper = ConnectionPool::Wrapper.new(pool: pool)
495
523
 
496
- pool.with { |r| r.do_work('with') }
497
- wrapper.do_work('wrapped')
524
+ pool.with { |r| r.do_work("with") }
525
+ wrapper.do_work("wrapped")
498
526
 
499
- assert_equal ['with', 'wrapped'], recorder.calls
527
+ assert_equal ["with", "wrapped"], recorder.calls
500
528
  end
501
529
 
502
530
  def test_stats_without_active_connection
@@ -513,4 +541,13 @@ class TestConnectionPool < Minitest::Test
513
541
  assert_equal(1, pool.available)
514
542
  end
515
543
  end
544
+
545
+ def test_stats_with_string_size
546
+ pool = ConnectionPool.new(size: "2") { NetworkConnection.new }
547
+
548
+ pool.with do
549
+ assert_equal(2, pool.size)
550
+ assert_equal(1, pool.available)
551
+ end
552
+ end
516
553
  end
@@ -1,7 +1,6 @@
1
- require_relative 'helper'
1
+ require_relative "helper"
2
2
 
3
3
  class TestConnectionPoolTimedStack < Minitest::Test
4
-
5
4
  def setup
6
5
  @stack = ConnectionPool::TimedStack.new { Object.new }
7
6
  end
@@ -35,18 +34,18 @@ class TestConnectionPoolTimedStack < Minitest::Test
35
34
  end
36
35
 
37
36
  def test_object_creation_fails
38
- stack = ConnectionPool::TimedStack.new(2) { raise 'failure' }
37
+ stack = ConnectionPool::TimedStack.new(2) { raise "failure" }
39
38
 
40
39
  begin
41
40
  stack.pop
42
41
  rescue => error
43
- assert_equal 'failure', error.message
42
+ assert_equal "failure", error.message
44
43
  end
45
44
 
46
45
  begin
47
46
  stack.pop
48
47
  rescue => error
49
- assert_equal 'failure', error.message
48
+ assert_equal "failure", error.message
50
49
  end
51
50
 
52
51
  refute_empty stack
@@ -63,19 +62,13 @@ class TestConnectionPoolTimedStack < Minitest::Test
63
62
  end
64
63
 
65
64
  def test_pop_empty
66
- e = assert_raises Timeout::Error do
67
- @stack.pop timeout: 0
68
- end
69
-
70
- assert_equal 'Waited 0 sec', e.message
65
+ e = assert_raises(ConnectionPool::TimeoutError) { @stack.pop timeout: 0 }
66
+ assert_equal "Waited 0 sec", e.message
71
67
  end
72
68
 
73
69
  def test_pop_empty_2_0_compatibility
74
- e = assert_raises Timeout::Error do
75
- @stack.pop 0
76
- end
77
-
78
- assert_equal 'Waited 0 sec', e.message
70
+ e = assert_raises(Timeout::Error) { @stack.pop 0 }
71
+ assert_equal "Waited 0 sec", e.message
79
72
  end
80
73
 
81
74
  def test_pop_full
@@ -88,11 +81,11 @@ class TestConnectionPoolTimedStack < Minitest::Test
88
81
  end
89
82
 
90
83
  def test_pop_wait
91
- thread = Thread.start do
84
+ thread = Thread.start {
92
85
  @stack.pop
93
- end
86
+ }
94
87
 
95
- Thread.pass while thread.status == 'run'
88
+ Thread.pass while thread.status == "run"
96
89
 
97
90
  object = Object.new
98
91
 
@@ -102,7 +95,7 @@ class TestConnectionPoolTimedStack < Minitest::Test
102
95
  end
103
96
 
104
97
  def test_pop_shutdown
105
- @stack.shutdown { }
98
+ @stack.shutdown {}
106
99
 
107
100
  assert_raises ConnectionPool::PoolShuttingDownError do
108
101
  @stack.pop
@@ -144,6 +137,4 @@ class TestConnectionPoolTimedStack < Minitest::Test
144
137
  refute_empty called
145
138
  assert_empty @stack
146
139
  end
147
-
148
140
  end
149
-
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.2.2
4
+ version: 2.2.3
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: 2018-05-24 00:00:00.000000000 Z
12
+ date: 2020-06-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -70,9 +70,9 @@ files:
70
70
  - Rakefile
71
71
  - connection_pool.gemspec
72
72
  - lib/connection_pool.rb
73
- - lib/connection_pool/monotonic_time.rb
74
73
  - lib/connection_pool/timed_stack.rb
75
74
  - lib/connection_pool/version.rb
75
+ - lib/connection_pool/wrapper.rb
76
76
  - test/helper.rb
77
77
  - test/test_connection_pool.rb
78
78
  - test/test_connection_pool_timed_stack.rb
@@ -95,8 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  requirements: []
98
- rubyforge_project:
99
- rubygems_version: 2.6.13
98
+ rubygems_version: 3.1.2
100
99
  signing_key:
101
100
  specification_version: 4
102
101
  summary: Generic connection pool for Ruby
@@ -1,66 +0,0 @@
1
- # Global monotonic clock from Concurrent Ruby 1.0.
2
- # Copyright (c) Jerry D'Antonio -- released under the MIT license.
3
- # Slightly modified; used with permission.
4
- # https://github.com/ruby-concurrency/concurrent-ruby
5
-
6
- require 'thread'
7
-
8
- class ConnectionPool
9
-
10
- class_definition = Class.new do
11
-
12
- if defined?(Process::CLOCK_MONOTONIC)
13
-
14
- # @!visibility private
15
- def get_time
16
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
17
- end
18
-
19
- elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
20
-
21
- # @!visibility private
22
- def get_time
23
- java.lang.System.nanoTime() / 1_000_000_000.0
24
- end
25
-
26
- else
27
-
28
- # @!visibility private
29
- def initialize
30
- @mutex = Mutex.new
31
- @last_time = Time.now.to_f
32
- end
33
-
34
- # @!visibility private
35
- def get_time
36
- @mutex.synchronize do
37
- now = Time.now.to_f
38
- if @last_time < now
39
- @last_time = now
40
- else # clock has moved back in time
41
- @last_time += 0.000_001
42
- end
43
- end
44
- end
45
- end
46
- end
47
-
48
- ##
49
- # Clock that cannot be set and represents monotonic time since
50
- # some unspecified starting point.
51
- #
52
- # @!visibility private
53
- GLOBAL_MONOTONIC_CLOCK = class_definition.new
54
- private_constant :GLOBAL_MONOTONIC_CLOCK
55
-
56
- class << self
57
- ##
58
- # Returns the current time a tracked by the application monotonic clock.
59
- #
60
- # @return [Float] The current monotonic time when `since` not given else
61
- # the elapsed monotonic time between `since` and the current time
62
- def monotonic_time
63
- GLOBAL_MONOTONIC_CLOCK.get_time
64
- end
65
- end
66
- end