connection_pool 2.2.2 → 2.4.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
- SHA1:
3
- metadata.gz: cf8177bf07f6c8e68b13f28416f6ccc0c64803af
4
- data.tar.gz: ff9c836ce5576d4d0cb1edf8d858a761f982e437
2
+ SHA256:
3
+ metadata.gz: e87682a6e57e8b0214de9c0713a7466a2b06399dc52d700fbf182cdf9e5b6606
4
+ data.tar.gz: d12337513b62d4677663403c512afad165275bdf848987182ce03637a1de6482
5
5
  SHA512:
6
- metadata.gz: 73bda4d8d0b3cc9daef5c93bb98b7649d811bd5c8f467e25c3aaf7d3353541225e7b30e1efd481a14e45f5c56b5fc846d49dabdd9a167702a71c4a9631a9b6a2
7
- data.tar.gz: a331275f67b3635e09792e646113e32bdc74254a2cdff032e972c6f2ebedd6391a1e508c36be7c4e33b40e2a07efe029a2ad0267c3ba4dc20b22813df86427bb
6
+ metadata.gz: eca2c1f8ebe52039f00df70ddfe5525cc0408acd8ae9849a8d1412bec670e7d3a05d3609db933e3e906cd83307d39f754dd5f1d7b48b50b847090b5bf485b55a
7
+ data.tar.gz: fc9a62b4b0ba5a406543e8f6399bd566f2f31c6c9a6ce2772e3550c1c2a75945c8a34defeda10c83e23cbfe5fe50d0e8861f57ea23935d7c97540aa97b04a635
data/Changes.md CHANGED
@@ -1,5 +1,34 @@
1
- connection\_pool changelog
2
- ---------------------------
1
+ # connection_pool Changelog
2
+
3
+ 2.4.0
4
+ ------
5
+
6
+ - Automatically drop all connections after fork [#166]
7
+
8
+ 2.3.0
9
+ ------
10
+
11
+ - Minimum Ruby version is now 2.5.0
12
+ - Add pool size to TimeoutError message
13
+
14
+ 2.2.5
15
+ ------
16
+
17
+ - Fix argument forwarding on Ruby 2.7 [#149]
18
+
19
+ 2.2.4
20
+ ------
21
+
22
+ - Add `reload` to close all connections, recreating them afterwards [Andrew Marshall, #140]
23
+ - Add `then` as a way to use a pool or a bare connection with the same code path [#138]
24
+
25
+ 2.2.3
26
+ ------
27
+
28
+ - Pool now throws `ConnectionPool::TimeoutError` on timeout. [#130]
29
+ - Use monotonic clock present in all modern Rubies [Tero Tasanen, #109]
30
+ - Remove code hacks necessary for JRuby 1.7
31
+ - Expose wrapped pool from ConnectionPool::Wrapper [Thomas Lecavelier, #113]
3
32
 
4
33
  2.2.2
5
34
  ------
data/README.md CHANGED
@@ -1,19 +1,17 @@
1
1
  connection\_pool
2
2
  =================
3
- [![Build Status](https://travis-ci.org/mperham/connection_pool.svg)](https://travis-ci.org/mperham/connection_pool)
3
+ [![Build Status](https://github.com/mperham/connection_pool/actions/workflows/ci.yml/badge.svg)](https://github.com/mperham/connection_pool/actions/workflows/ci.yml)
4
4
 
5
5
  Generic connection pooling for Ruby.
6
6
 
7
- MongoDB has its own connection pool. ActiveRecord has its own connection pool.
8
- This is a generic connection pool that can be used with anything, e.g. Redis,
9
- Dalli and other Ruby network clients.
10
-
7
+ MongoDB has its own connection pool.
8
+ ActiveRecord has its own connection pool.
9
+ This is a generic connection pool that can be used with anything, e.g. Redis, Dalli and other Ruby network clients.
11
10
 
12
11
  Usage
13
12
  -----
14
13
 
15
- Create a pool of objects to share amongst the fibers or threads in your Ruby
16
- application:
14
+ Create a pool of objects to share amongst the fibers or threads in your Ruby application:
17
15
 
18
16
  ``` ruby
19
17
  $memcached = ConnectionPool.new(size: 5, timeout: 5) { Dalli::Client.new }
@@ -28,8 +26,17 @@ end
28
26
  ```
29
27
 
30
28
  If all the objects in the connection pool are in use, `with` will block
31
- until one becomes available. If no object is available within `:timeout` seconds,
32
- `with` will raise a `Timeout::Error`.
29
+ until one becomes available.
30
+ If no object is available within `:timeout` seconds,
31
+ `with` will raise a `ConnectionPool::TimeoutError` (a subclass of `Timeout::Error`).
32
+
33
+ You can also use `ConnectionPool#then` to support _both_ a
34
+ connection pool and a raw client.
35
+
36
+ ```ruby
37
+ # Compatible with a raw Redis::Client, and ConnectionPool Redis
38
+ $redis.then { |r| r.set 'foo' 'bar' }
39
+ ```
33
40
 
34
41
  Optionally, you can specify a timeout override using the with-block semantics:
35
42
 
@@ -40,26 +47,23 @@ end
40
47
  ```
41
48
 
42
49
  This will only modify the resource-get timeout for this particular
43
- invocation. This is useful if you want to fail-fast on certain non critical
44
- sections when a resource is not available, or conversely if you are comfortable
45
- blocking longer on a particular resource. This is not implemented in the below
46
- `ConnectionPool::Wrapper` class.
50
+ invocation.
51
+ This is useful if you want to fail-fast on certain non-critical
52
+ sections when a resource is not available, or conversely if you are comfortable blocking longer on a particular resource.
53
+ This is not implemented in the `ConnectionPool::Wrapper` class.
47
54
 
48
55
  ## Migrating to a Connection Pool
49
56
 
50
- You can use `ConnectionPool::Wrapper` to wrap a single global connection,
51
- making it easier to migrate existing connection code over time:
57
+ You can use `ConnectionPool::Wrapper` to wrap a single global connection, making it easier to migrate existing connection code over time:
52
58
 
53
59
  ``` ruby
54
- $redis = ConnectionPool::Wrapper.new(size: 5, timeout: 3) { Redis.connect }
60
+ $redis = ConnectionPool::Wrapper.new(size: 5, timeout: 3) { Redis.new }
55
61
  $redis.sadd('foo', 1)
56
62
  $redis.smembers('foo')
57
63
  ```
58
64
 
59
- The wrapper uses `method_missing` to checkout a connection, run the requested
60
- method and then immediately check the connection back into the pool. It's
61
- **not** high-performance so you'll want to port your performance sensitive code
62
- to use `with` as soon as possible.
65
+ The wrapper uses `method_missing` to checkout a connection, run the requested method and then immediately check the connection back into the pool.
66
+ It's **not** high-performance so you'll want to port your performance sensitive code to use `with` as soon as possible.
63
67
 
64
68
  ``` ruby
65
69
  $redis.with do |conn|
@@ -68,40 +72,64 @@ $redis.with do |conn|
68
72
  end
69
73
  ```
70
74
 
71
- Once you've ported your entire system to use `with`, you can simply remove
72
- `Wrapper` and use the simpler and faster `ConnectionPool`.
75
+ Once you've ported your entire system to use `with`, you can simply remove `Wrapper` and use the simpler and faster `ConnectionPool`.
73
76
 
74
77
 
75
78
  ## Shutdown
76
79
 
77
80
  You can shut down a ConnectionPool instance once it should no longer be used.
78
- Further checkout attempts will immediately raise an error but existing checkouts
79
- will work.
81
+ Further checkout attempts will immediately raise an error but existing checkouts will work.
80
82
 
81
83
  ```ruby
82
84
  cp = ConnectionPool.new { Redis.new }
83
- cp.shutdown { |conn| conn.quit }
85
+ cp.shutdown { |c| c.close }
84
86
  ```
85
87
 
86
88
  Shutting down a connection pool will block until all connections are checked in and closed.
87
- **Note that shutting down is completely optional**; Ruby's garbage collector will reclaim
88
- unreferenced pools under normal circumstances.
89
+ **Note that shutting down is completely optional**; Ruby's garbage collector will reclaim unreferenced pools under normal circumstances.
90
+
91
+ ## Reload
92
+
93
+ You can reload a ConnectionPool instance in the case it is desired to close all connections to the pool and, unlike `shutdown`, afterwards recreate connections so the pool may continue to be used.
94
+ Reloading may be useful after forking the process.
95
+
96
+ ```ruby
97
+ cp = ConnectionPool.new { Redis.new }
98
+ cp.reload { |conn| conn.quit }
99
+ cp.with { |conn| conn.get('some-count') }
100
+ ```
101
+
102
+ Like `shutdown`, this will block until all connections are checked in and closed.
103
+
104
+ ## Current State
105
+
106
+ There are several methods that return information about a pool.
89
107
 
108
+ ```ruby
109
+ cp = ConnectionPool.new(size: 10) { Redis.new }
110
+ cp.size # => 10
111
+ cp.available # => 10
112
+
113
+ cp.with do |conn|
114
+ cp.size # => 10
115
+ cp.available # => 9
116
+ end
117
+ ```
90
118
 
91
119
  Notes
92
120
  -----
93
121
 
94
122
  - Connections are lazily created as needed.
95
123
  - There is no provision for repairing or checking the health of a connection;
96
- connections should be self-repairing. This is true of the Dalli and Redis
124
+ connections should be self-repairing. This is true of the Dalli and Redis
97
125
  clients.
98
126
  - **WARNING**: Don't ever use `Timeout.timeout` in your Ruby code or you will see
99
- occasional silent corruption and mysterious errors. The Timeout API is unsafe
100
- and cannot be used correctly, ever. Use proper socket timeout options as
127
+ occasional silent corruption and mysterious errors. The Timeout API is unsafe
128
+ and cannot be used correctly, ever. Use proper socket timeout options as
101
129
  exposed by Net::HTTP, Redis, Dalli, etc.
102
130
 
103
131
 
104
132
  Author
105
133
  ------
106
134
 
107
- Mike Perham, [@mperham](https://twitter.com/mperham), <http://mikeperham.com>
135
+ Mike Perham, [@getajobmike](https://twitter.com/getajobmike), <https://www.mikeperham.com>
@@ -1,21 +1,22 @@
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 = ["Changes.md", "LICENSE", "README.md", "connection_pool.gemspec",
13
+ "lib/connection_pool.rb", "lib/connection_pool/timed_stack.rb",
14
+ "lib/connection_pool/version.rb", "lib/connection_pool/wrapper.rb"]
15
+ s.executables = []
16
16
  s.require_paths = ["lib"]
17
17
  s.license = "MIT"
18
- s.add_development_dependency 'bundler'
19
- s.add_development_dependency 'minitest', '>= 5.0.0'
20
- s.add_development_dependency 'rake'
18
+ s.add_development_dependency "bundler"
19
+ s.add_development_dependency "minitest", ">= 5.0.0"
20
+ s.add_development_dependency "rake"
21
+ s.required_ruby_version = ">= 2.5.0"
21
22
  end
@@ -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
@@ -25,7 +15,7 @@ class ConnectionPool::PoolShuttingDownError < RuntimeError; end
25
15
  #
26
16
  # conn = ts.pop
27
17
  # ts.pop timeout: 5
28
- # #=> raises Timeout::Error after 5 seconds
18
+ # #=> raises ConnectionPool::TimeoutError after 5 seconds
29
19
 
30
20
  class ConnectionPool::TimedStack
31
21
  attr_reader :max
@@ -39,8 +29,8 @@ class ConnectionPool::TimedStack
39
29
  @created = 0
40
30
  @que = []
41
31
  @max = size
42
- @mutex = Mutex.new
43
- @resource = ConditionVariable.new
32
+ @mutex = Thread::Mutex.new
33
+ @resource = Thread::ConditionVariable.new
44
34
  @shutdown_block = nil
45
35
  end
46
36
 
@@ -64,7 +54,7 @@ class ConnectionPool::TimedStack
64
54
  ##
65
55
  # Retrieves a connection from the stack. If a connection is available it is
66
56
  # immediately returned. If no connection is available within the given
67
- # timeout a Timeout::Error is raised.
57
+ # timeout a ConnectionPool::TimeoutError is raised.
68
58
  #
69
59
  # +:timeout+ is the only checked entry in +options+ and is preferred over
70
60
  # the +timeout+ argument (which will be removed in a future release). Other
@@ -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,25 +73,28 @@ 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, #{length}/#{@max} available" if to_wait <= 0
88
78
  @resource.wait(@mutex, to_wait)
89
79
  end
90
80
  end
91
81
  end
92
82
 
93
83
  ##
94
- # Shuts down the TimedStack which prevents connections from being checked
95
- # out. The +block+ is called once for each connection on the stack.
84
+ # Shuts down the TimedStack by passing each connection to +block+ and then
85
+ # removing it from the pool. Attempting to checkout a connection after
86
+ # shutdown will raise +ConnectionPool::PoolShuttingDownError+ unless
87
+ # +:reload+ is +true+.
96
88
 
97
- def shutdown(&block)
98
- raise ArgumentError, "shutdown must receive a block" unless block_given?
89
+ def shutdown(reload: false, &block)
90
+ raise ArgumentError, "shutdown must receive a block" unless block
99
91
 
100
92
  @mutex.synchronize do
101
93
  @shutdown_block = block
102
94
  @resource.broadcast
103
95
 
104
96
  shutdown_connections
97
+ @shutdown_block = nil if reload
105
98
  end
106
99
  end
107
100
 
@@ -121,6 +114,10 @@ class ConnectionPool::TimedStack
121
114
 
122
115
  private
123
116
 
117
+ def current_time
118
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
119
+ end
120
+
124
121
  ##
125
122
  # This is an extension point for TimedStack and is called with a mutex.
126
123
  #
@@ -149,6 +146,7 @@ class ConnectionPool::TimedStack
149
146
  conn = fetch_connection(options)
150
147
  @shutdown_block.call(conn)
151
148
  end
149
+ @created = 0
152
150
  end
153
151
 
154
152
  ##
@@ -1,3 +1,3 @@
1
1
  class ConnectionPool
2
- VERSION = "2.2.2"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -0,0 +1,56 @@
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/MissingRespondToMissing
34
+ if ::RUBY_VERSION >= "3.0.0"
35
+ def method_missing(name, *args, **kwargs, &block)
36
+ with do |connection|
37
+ connection.send(name, *args, **kwargs, &block)
38
+ end
39
+ end
40
+ elsif ::RUBY_VERSION >= "2.7.0"
41
+ ruby2_keywords def method_missing(name, *args, &block)
42
+ with do |connection|
43
+ connection.send(name, *args, &block)
44
+ end
45
+ end
46
+ else
47
+ def method_missing(name, *args, &block)
48
+ with do |connection|
49
+ connection.send(name, *args, &block)
50
+ end
51
+ end
52
+ end
53
+ # rubocop:enable Style/MethodMissingSuper
54
+ # rubocop:enable Style/MissingRespondToMissing
55
+ end
56
+ end
@@ -1,14 +1,20 @@
1
- require_relative 'connection_pool/version'
2
- require_relative 'connection_pool/timed_stack'
1
+ require "timeout"
2
+ require_relative "connection_pool/version"
3
3
 
4
+ class ConnectionPool
5
+ class Error < ::RuntimeError; end
6
+
7
+ class PoolShuttingDownError < ::ConnectionPool::Error; end
8
+
9
+ class TimeoutError < ::Timeout::Error; end
10
+ end
4
11
 
5
- # Generic connection pool class for e.g. sharing a limited number of network connections
6
- # among many threads. Note: Connections are lazily created.
12
+ # Generic connection pool class for sharing a limited number of objects or network connections
13
+ # among many threads. Note: pool elements are lazily created.
7
14
  #
8
15
  # Example usage with block (faster):
9
16
  #
10
17
  # @pool = ConnectionPool.new { Redis.new }
11
- #
12
18
  # @pool.with do |redis|
13
19
  # redis.lpop('my-list') if redis.llen('my-list') > 0
14
20
  # end
@@ -34,29 +40,65 @@ require_relative 'connection_pool/timed_stack'
34
40
  class ConnectionPool
35
41
  DEFAULTS = {size: 5, timeout: 5}
36
42
 
37
- class Error < RuntimeError
38
- end
39
-
40
43
  def self.wrap(options, &block)
41
44
  Wrapper.new(options, &block)
42
45
  end
43
46
 
47
+ if Process.respond_to?(:fork)
48
+ INSTANCES = ObjectSpace::WeakMap.new
49
+ private_constant :INSTANCES
50
+
51
+ def self.after_fork
52
+ INSTANCES.values.each do |pool|
53
+ # We're on after fork, so we know all other threads are dead.
54
+ # All we need to do is to ensure the main thread doesn't have a
55
+ # checked out connection
56
+ pool.checkin(force: true)
57
+
58
+ pool.reload do |connection|
59
+ # Unfortunately we don't know what method to call to close the connection,
60
+ # so we try the most common one.
61
+ connection.close if connection.respond_to?(:close)
62
+ end
63
+ end
64
+ nil
65
+ end
66
+
67
+ if ::Process.respond_to?(:_fork) # MRI 3.1+
68
+ module ForkTracker
69
+ def _fork
70
+ pid = super
71
+ if pid == 0
72
+ ConnectionPool.after_fork
73
+ end
74
+ pid
75
+ end
76
+ end
77
+ Process.singleton_class.prepend(ForkTracker)
78
+ end
79
+ else
80
+ INSTANCES = nil
81
+ private_constant :INSTANCES
82
+
83
+ def self.after_fork
84
+ # noop
85
+ end
86
+ end
87
+
44
88
  def initialize(options = {}, &block)
45
- raise ArgumentError, 'Connection pool requires a block' unless block
89
+ raise ArgumentError, "Connection pool requires a block" unless block
46
90
 
47
91
  options = DEFAULTS.merge(options)
48
92
 
49
- @size = options.fetch(:size)
93
+ @size = Integer(options.fetch(:size))
50
94
  @timeout = options.fetch(:timeout)
51
95
 
52
96
  @available = TimedStack.new(@size, &block)
53
- @key = :"current-#{@available.object_id}"
54
- @key_count = :"current-#{@available.object_id}-count"
97
+ @key = :"pool-#{@available.object_id}"
98
+ @key_count = :"pool-#{@available.object_id}-count"
99
+ INSTANCES[self] = self if INSTANCES
55
100
  end
56
101
 
57
- if Thread.respond_to?(:handle_interrupt)
58
-
59
- # MRI
60
102
  def with(options = {})
61
103
  Thread.handle_interrupt(Exception => :never) do
62
104
  conn = checkout(options)
@@ -69,93 +111,60 @@ if Thread.respond_to?(:handle_interrupt)
69
111
  end
70
112
  end
71
113
  end
72
-
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
114
+ alias_method :then, :with
86
115
 
87
116
  def checkout(options = {})
88
117
  if ::Thread.current[@key]
89
- ::Thread.current[@key_count]+= 1
118
+ ::Thread.current[@key_count] += 1
90
119
  ::Thread.current[@key]
91
120
  else
92
- ::Thread.current[@key_count]= 1
93
- ::Thread.current[@key]= @available.pop(options[:timeout] || @timeout)
121
+ ::Thread.current[@key_count] = 1
122
+ ::Thread.current[@key] = @available.pop(options[:timeout] || @timeout)
94
123
  end
95
124
  end
96
125
 
97
- def checkin
126
+ def checkin(force: false)
98
127
  if ::Thread.current[@key]
99
- if ::Thread.current[@key_count] == 1
128
+ if ::Thread.current[@key_count] == 1 || force
100
129
  @available.push(::Thread.current[@key])
101
- ::Thread.current[@key]= nil
130
+ ::Thread.current[@key] = nil
131
+ ::Thread.current[@key_count] = nil
102
132
  else
103
- ::Thread.current[@key_count]-= 1
133
+ ::Thread.current[@key_count] -= 1
104
134
  end
105
- else
106
- raise ConnectionPool::Error, 'no connections are checked out'
135
+ elsif !force
136
+ raise ConnectionPool::Error, "no connections are checked out"
107
137
  end
108
138
 
109
139
  nil
110
140
  end
111
141
 
142
+ ##
143
+ # Shuts down the ConnectionPool by passing each connection to +block+ and
144
+ # then removing it from the pool. Attempting to checkout a connection after
145
+ # shutdown will raise +ConnectionPool::PoolShuttingDownError+.
146
+
112
147
  def shutdown(&block)
113
148
  @available.shutdown(&block)
114
149
  end
115
150
 
116
- # Size of this connection pool
117
- def size
118
- @size
151
+ ##
152
+ # Reloads the ConnectionPool by passing each connection to +block+ and then
153
+ # removing it the pool. Subsequent checkouts will create new connections as
154
+ # needed.
155
+
156
+ def reload(&block)
157
+ @available.shutdown(reload: true, &block)
119
158
  end
120
159
 
160
+ # Size of this connection pool
161
+ attr_reader :size
162
+
121
163
  # Number of pool entries available for checkout at this instant.
122
164
  def available
123
165
  @available.length
124
166
  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
167
  end
168
+
169
+ require_relative "connection_pool/timed_stack"
170
+ require_relative "connection_pool/wrapper"