connection_pool 2.2.0 → 2.2.5
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 +5 -5
- data/.github/workflows/ci.yml +26 -0
- data/Changes.md +32 -2
- data/README.md +54 -20
- data/Rakefile +3 -3
- data/connection_pool.gemspec +14 -14
- data/lib/connection_pool.rb +50 -72
- data/lib/connection_pool/timed_stack.rb +18 -18
- data/lib/connection_pool/version.rb +1 -1
- data/lib/connection_pool/wrapper.rb +57 -0
- data/test/helper.rb +4 -4
- data/test/test_connection_pool.rb +187 -104
- data/test/test_connection_pool_timed_stack.rb +22 -21
- metadata +9 -9
- data/.travis.yml +0 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: '0993b72c233b027a1229d532a126b4a1623ef3f146a7b56502c539084f9a228d'
|
|
4
|
+
data.tar.gz: 274efa04fc445ca0044f62da29484a4ee9fb5e02b5f213fb873fedfd63cadff0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17c5bea167386115e8672b394138e0f66b55e6371b803dcfee7be08e51c84353aa9cd0257f169ae04053bc95be6b0c9b06576579f4915e68271146b1c9d602a5
|
|
7
|
+
data.tar.gz: 4eeccb9eaf397e8e386a41f81005b10d43d7441297661ab0d7656b6be30ac7ff1e751a95ed5c5b5a412124a29a0af3f5c90ae2882d70d3fa29d9dc8b2df412e3
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
continue-on-error: ${{ matrix.experimental }}
|
|
9
|
+
strategy:
|
|
10
|
+
fail-fast: false
|
|
11
|
+
matrix:
|
|
12
|
+
ruby: ["2.4", "2.5", "2.6", "2.7", "3.0", "jruby"]
|
|
13
|
+
experimental: [false]
|
|
14
|
+
include:
|
|
15
|
+
- ruby: "truffleruby"
|
|
16
|
+
experimental: true
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v2
|
|
19
|
+
- uses: ruby/setup-ruby@v1
|
|
20
|
+
with:
|
|
21
|
+
ruby-version: ${{matrix.ruby}}
|
|
22
|
+
bundler-cache: true
|
|
23
|
+
|
|
24
|
+
- name: Run tests
|
|
25
|
+
timeout-minutes: 5
|
|
26
|
+
run: ${{matrix.env}} bundle exec rake
|
data/Changes.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# connection_pool Changelog
|
|
2
|
+
|
|
3
|
+
2.2.5
|
|
4
|
+
------
|
|
5
|
+
|
|
6
|
+
- Fix argument forwarding on Ruby 2.7 [#149]
|
|
7
|
+
|
|
8
|
+
2.2.4
|
|
9
|
+
------
|
|
10
|
+
|
|
11
|
+
- Add `reload` to close all connections, recreating them afterwards [Andrew Marshall, #140]
|
|
12
|
+
- Add `then` as a way to use a pool or a bare connection with the same code path [#138]
|
|
13
|
+
|
|
14
|
+
2.2.3
|
|
15
|
+
------
|
|
16
|
+
|
|
17
|
+
- Pool now throws `ConnectionPool::TimeoutError` on timeout. [#130]
|
|
18
|
+
- Use monotonic clock present in all modern Rubies [Tero Tasanen, #109]
|
|
19
|
+
- Remove code hacks necessary for JRuby 1.7
|
|
20
|
+
- Expose wrapped pool from ConnectionPool::Wrapper [Thomas Lecavelier, #113]
|
|
21
|
+
|
|
22
|
+
2.2.2
|
|
23
|
+
------
|
|
24
|
+
|
|
25
|
+
- Add pool `size` and `available` accessors for metrics and monitoring
|
|
26
|
+
purposes [#97, robholland]
|
|
27
|
+
|
|
28
|
+
2.2.1
|
|
29
|
+
------
|
|
30
|
+
|
|
31
|
+
- Allow CP::Wrapper to use an existing pool [#87, etiennebarrie]
|
|
32
|
+
- Use monotonic time for more accurate timeouts [#84, jdantonio]
|
|
3
33
|
|
|
4
34
|
2.2.0
|
|
5
35
|
------
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
connection\_pool
|
|
2
2
|
=================
|
|
3
|
-
[](https://github.com/mperham/connection_pool/actions/workflows/ci.yml)
|
|
4
4
|
|
|
5
5
|
Generic connection pooling for Ruby.
|
|
6
6
|
|
|
@@ -8,11 +8,6 @@ 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
|
-
|
|
16
11
|
|
|
17
12
|
Usage
|
|
18
13
|
-----
|
|
@@ -36,6 +31,14 @@ If all the objects in the connection pool are in use, `with` will block
|
|
|
36
31
|
until one becomes available. If no object is available within `:timeout` seconds,
|
|
37
32
|
`with` will raise a `Timeout::Error`.
|
|
38
33
|
|
|
34
|
+
You can also use `ConnectionPool#then` to support _both_ a
|
|
35
|
+
connection pool and a raw client (requires Ruby 2.5+).
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
# Compatible with a raw Redis::Client, and ConnectionPool Redis
|
|
39
|
+
$redis.then { |r| r.set 'foo' 'bar' }
|
|
40
|
+
```
|
|
41
|
+
|
|
39
42
|
Optionally, you can specify a timeout override using the with-block semantics:
|
|
40
43
|
|
|
41
44
|
``` ruby
|
|
@@ -50,11 +53,13 @@ sections when a resource is not available, or conversely if you are comfortable
|
|
|
50
53
|
blocking longer on a particular resource. This is not implemented in the below
|
|
51
54
|
`ConnectionPool::Wrapper` class.
|
|
52
55
|
|
|
56
|
+
## Migrating to a Connection Pool
|
|
57
|
+
|
|
53
58
|
You can use `ConnectionPool::Wrapper` to wrap a single global connection,
|
|
54
|
-
making it easier to
|
|
59
|
+
making it easier to migrate existing connection code over time:
|
|
55
60
|
|
|
56
61
|
``` ruby
|
|
57
|
-
$redis = ConnectionPool::Wrapper.new(size: 5, timeout: 3) { Redis.
|
|
62
|
+
$redis = ConnectionPool::Wrapper.new(size: 5, timeout: 3) { Redis.new }
|
|
58
63
|
$redis.sadd('foo', 1)
|
|
59
64
|
$redis.smembers('foo')
|
|
60
65
|
```
|
|
@@ -74,38 +79,67 @@ end
|
|
|
74
79
|
Once you've ported your entire system to use `with`, you can simply remove
|
|
75
80
|
`Wrapper` and use the simpler and faster `ConnectionPool`.
|
|
76
81
|
|
|
82
|
+
|
|
83
|
+
## Shutdown
|
|
84
|
+
|
|
77
85
|
You can shut down a ConnectionPool instance once it should no longer be used.
|
|
78
86
|
Further checkout attempts will immediately raise an error but existing checkouts
|
|
79
87
|
will work.
|
|
80
88
|
|
|
81
89
|
```ruby
|
|
82
90
|
cp = ConnectionPool.new { Redis.new }
|
|
83
|
-
cp.shutdown { |conn| conn.
|
|
91
|
+
cp.shutdown { |conn| conn.quit }
|
|
84
92
|
```
|
|
85
93
|
|
|
86
94
|
Shutting down a connection pool will block until all connections are checked in and closed.
|
|
87
|
-
Note that shutting down is completely optional
|
|
95
|
+
**Note that shutting down is completely optional**; Ruby's garbage collector will reclaim
|
|
88
96
|
unreferenced pools under normal circumstances.
|
|
89
97
|
|
|
98
|
+
## Reload
|
|
99
|
+
|
|
100
|
+
You can reload a ConnectionPool instance in the case it is desired to close all
|
|
101
|
+
connections to the pool and, unlike `shutdown`, afterwards recreate connections
|
|
102
|
+
so the pool may continue to be used. Reloading may be useful after forking the
|
|
103
|
+
process.
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
cp = ConnectionPool.new { Redis.new }
|
|
107
|
+
cp.reload { |conn| conn.quit }
|
|
108
|
+
cp.with { |conn| conn.get('some-count') }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Like `shutdown`, this will block until all connections are checked in and
|
|
112
|
+
closed.
|
|
113
|
+
|
|
114
|
+
## Current State
|
|
115
|
+
|
|
116
|
+
There are several methods that return information about a pool.
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
cp = ConnectionPool.new(size: 10) { Redis.new }
|
|
120
|
+
cp.size # => 10
|
|
121
|
+
cp.available # => 10
|
|
122
|
+
|
|
123
|
+
cp.with do |conn|
|
|
124
|
+
cp.size # => 10
|
|
125
|
+
cp.available # => 9
|
|
126
|
+
end
|
|
127
|
+
```
|
|
90
128
|
|
|
91
129
|
Notes
|
|
92
130
|
-----
|
|
93
131
|
|
|
94
132
|
- Connections are lazily created as needed.
|
|
95
133
|
- There is no provision for repairing or checking the health of a connection;
|
|
96
|
-
connections should be self-repairing.
|
|
134
|
+
connections should be self-repairing. This is true of the Dalli and Redis
|
|
97
135
|
clients.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
$ gem install connection_pool
|
|
105
|
-
```
|
|
136
|
+
- **WARNING**: Don't ever use `Timeout.timeout` in your Ruby code or you will see
|
|
137
|
+
occasional silent corruption and mysterious errors. The Timeout API is unsafe
|
|
138
|
+
and cannot be used correctly, ever. Use proper socket timeout options as
|
|
139
|
+
exposed by Net::HTTP, Redis, Dalli, etc.
|
|
106
140
|
|
|
107
141
|
|
|
108
142
|
Author
|
|
109
143
|
------
|
|
110
144
|
|
|
111
|
-
Mike Perham, [@
|
|
145
|
+
Mike Perham, [@getajobmike](https://twitter.com/getajobmike), <https://www.mikeperham.com>
|
data/Rakefile
CHANGED
data/connection_pool.gemspec
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
1
|
require "./lib/connection_pool/version"
|
|
3
2
|
|
|
4
3
|
Gem::Specification.new do |s|
|
|
5
|
-
s.name
|
|
6
|
-
s.version
|
|
7
|
-
s.platform
|
|
8
|
-
s.authors
|
|
9
|
-
s.email
|
|
10
|
-
s.homepage
|
|
11
|
-
s.description = s.summary =
|
|
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
|
|
14
|
-
s.test_files
|
|
15
|
-
s.executables
|
|
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
|
|
19
|
-
s.add_development_dependency
|
|
20
|
-
s.add_development_dependency
|
|
17
|
+
s.add_development_dependency "bundler"
|
|
18
|
+
s.add_development_dependency "minitest", ">= 5.0.0"
|
|
19
|
+
s.add_development_dependency "rake"
|
|
20
|
+
s.required_ruby_version = ">= 2.2.0"
|
|
21
21
|
end
|
data/lib/connection_pool.rb
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
|
6
|
-
# among many threads. Note:
|
|
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
|
|
15
19
|
#
|
|
16
20
|
# Using optional timeout override (for that single invocation)
|
|
17
21
|
#
|
|
18
|
-
# @pool.with(:
|
|
22
|
+
# @pool.with(timeout: 2.0) do |redis|
|
|
19
23
|
# redis.lpop('my-list') if redis.llen('my-list') > 0
|
|
20
24
|
# end
|
|
21
25
|
#
|
|
@@ -34,28 +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,
|
|
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 = :"
|
|
54
|
+
@key = :"pool-#{@available.object_id}"
|
|
55
|
+
@key_count = :"pool-#{@available.object_id}-count"
|
|
54
56
|
end
|
|
55
57
|
|
|
56
|
-
if Thread.respond_to?(:handle_interrupt)
|
|
57
|
-
|
|
58
|
-
# MRI
|
|
59
58
|
def with(options = {})
|
|
60
59
|
Thread.handle_interrupt(Exception => :never) do
|
|
61
60
|
conn = checkout(options)
|
|
@@ -68,81 +67,60 @@ if Thread.respond_to?(:handle_interrupt)
|
|
|
68
67
|
end
|
|
69
68
|
end
|
|
70
69
|
end
|
|
71
|
-
|
|
72
|
-
else
|
|
73
|
-
|
|
74
|
-
# jruby 1.7.x
|
|
75
|
-
def with(options = {})
|
|
76
|
-
conn = checkout(options)
|
|
77
|
-
begin
|
|
78
|
-
yield conn
|
|
79
|
-
ensure
|
|
80
|
-
checkin
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
end
|
|
70
|
+
alias then with
|
|
85
71
|
|
|
86
72
|
def checkout(options = {})
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
@
|
|
73
|
+
if ::Thread.current[@key]
|
|
74
|
+
::Thread.current[@key_count] += 1
|
|
75
|
+
::Thread.current[@key]
|
|
90
76
|
else
|
|
91
|
-
|
|
77
|
+
::Thread.current[@key_count] = 1
|
|
78
|
+
::Thread.current[@key] = @available.pop(options[:timeout] || @timeout)
|
|
92
79
|
end
|
|
93
|
-
|
|
94
|
-
stack.push conn
|
|
95
|
-
conn
|
|
96
80
|
end
|
|
97
81
|
|
|
98
82
|
def checkin
|
|
99
|
-
|
|
100
|
-
|
|
83
|
+
if ::Thread.current[@key]
|
|
84
|
+
if ::Thread.current[@key_count] == 1
|
|
85
|
+
@available.push(::Thread.current[@key])
|
|
86
|
+
::Thread.current[@key] = nil
|
|
87
|
+
::Thread.current[@key_count] = nil
|
|
88
|
+
else
|
|
89
|
+
::Thread.current[@key_count] -= 1
|
|
90
|
+
end
|
|
91
|
+
else
|
|
92
|
+
raise ConnectionPool::Error, "no connections are checked out"
|
|
93
|
+
end
|
|
101
94
|
|
|
102
95
|
nil
|
|
103
96
|
end
|
|
104
97
|
|
|
98
|
+
##
|
|
99
|
+
# Shuts down the ConnectionPool by passing each connection to +block+ and
|
|
100
|
+
# then removing it from the pool. Attempting to checkout a connection after
|
|
101
|
+
# shutdown will raise +ConnectionPool::PoolShuttingDownError+.
|
|
102
|
+
|
|
105
103
|
def shutdown(&block)
|
|
106
104
|
@available.shutdown(&block)
|
|
107
105
|
end
|
|
108
106
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
raise ConnectionPool::Error, 'no connections are checked out'
|
|
114
|
-
else
|
|
115
|
-
stack.pop
|
|
116
|
-
end
|
|
117
|
-
end
|
|
107
|
+
##
|
|
108
|
+
# Reloads the ConnectionPool by passing each connection to +block+ and then
|
|
109
|
+
# removing it the pool. Subsequent checkouts will create new connections as
|
|
110
|
+
# needed.
|
|
118
111
|
|
|
119
|
-
def
|
|
120
|
-
|
|
112
|
+
def reload(&block)
|
|
113
|
+
@available.shutdown(reload: true, &block)
|
|
121
114
|
end
|
|
122
115
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def initialize(options = {}, &block)
|
|
127
|
-
@pool = ::ConnectionPool.new(options, &block)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def with(&block)
|
|
131
|
-
@pool.with(&block)
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def pool_shutdown(&block)
|
|
135
|
-
@pool.shutdown(&block)
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def respond_to?(id, *args)
|
|
139
|
-
METHODS.include?(id) || with { |c| c.respond_to?(id, *args) }
|
|
140
|
-
end
|
|
116
|
+
# Size of this connection pool
|
|
117
|
+
attr_reader :size
|
|
141
118
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
end
|
|
146
|
-
end
|
|
119
|
+
# Number of pool entries available for checkout at this instant.
|
|
120
|
+
def available
|
|
121
|
+
@available.length
|
|
147
122
|
end
|
|
148
123
|
end
|
|
124
|
+
|
|
125
|
+
require "connection_pool/timed_stack"
|
|
126
|
+
require "connection_pool/wrapper"
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
require 'thread'
|
|
2
|
-
require 'timeout'
|
|
3
|
-
|
|
4
|
-
##
|
|
5
|
-
# Raised when you attempt to retrieve a connection from a pool that has been
|
|
6
|
-
# shut down.
|
|
7
|
-
|
|
8
|
-
class ConnectionPool::PoolShuttingDownError < RuntimeError; end
|
|
9
|
-
|
|
10
1
|
##
|
|
11
2
|
# The TimedStack manages a pool of homogeneous connections (or any resource
|
|
12
3
|
# you wish to manage). Connections are created lazily up to a given maximum
|
|
@@ -24,9 +15,10 @@ class ConnectionPool::PoolShuttingDownError < RuntimeError; end
|
|
|
24
15
|
#
|
|
25
16
|
# conn = ts.pop
|
|
26
17
|
# ts.pop timeout: 5
|
|
27
|
-
# #=> raises
|
|
18
|
+
# #=> raises ConnectionPool::TimeoutError after 5 seconds
|
|
28
19
|
|
|
29
20
|
class ConnectionPool::TimedStack
|
|
21
|
+
attr_reader :max
|
|
30
22
|
|
|
31
23
|
##
|
|
32
24
|
# Creates a new pool with +size+ connections that are created from the given
|
|
@@ -57,12 +49,12 @@ class ConnectionPool::TimedStack
|
|
|
57
49
|
@resource.broadcast
|
|
58
50
|
end
|
|
59
51
|
end
|
|
60
|
-
|
|
52
|
+
alias << push
|
|
61
53
|
|
|
62
54
|
##
|
|
63
55
|
# Retrieves a connection from the stack. If a connection is available it is
|
|
64
56
|
# immediately returned. If no connection is available within the given
|
|
65
|
-
# timeout a
|
|
57
|
+
# timeout a ConnectionPool::TimeoutError is raised.
|
|
66
58
|
#
|
|
67
59
|
# +:timeout+ is the only checked entry in +options+ and is preferred over
|
|
68
60
|
# the +timeout+ argument (which will be removed in a future release). Other
|
|
@@ -72,7 +64,7 @@ class ConnectionPool::TimedStack
|
|
|
72
64
|
options, timeout = timeout, 0.5 if Hash === timeout
|
|
73
65
|
timeout = options.fetch :timeout, timeout
|
|
74
66
|
|
|
75
|
-
deadline =
|
|
67
|
+
deadline = current_time + timeout
|
|
76
68
|
@mutex.synchronize do
|
|
77
69
|
loop do
|
|
78
70
|
raise ConnectionPool::PoolShuttingDownError if @shutdown_block
|
|
@@ -81,18 +73,20 @@ class ConnectionPool::TimedStack
|
|
|
81
73
|
connection = try_create(options)
|
|
82
74
|
return connection if connection
|
|
83
75
|
|
|
84
|
-
to_wait = deadline -
|
|
85
|
-
raise
|
|
76
|
+
to_wait = deadline - current_time
|
|
77
|
+
raise ConnectionPool::TimeoutError, "Waited #{timeout} sec" if to_wait <= 0
|
|
86
78
|
@resource.wait(@mutex, to_wait)
|
|
87
79
|
end
|
|
88
80
|
end
|
|
89
81
|
end
|
|
90
82
|
|
|
91
83
|
##
|
|
92
|
-
# Shuts down the TimedStack
|
|
93
|
-
#
|
|
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+.
|
|
94
88
|
|
|
95
|
-
def shutdown(&block)
|
|
89
|
+
def shutdown(reload: false, &block)
|
|
96
90
|
raise ArgumentError, "shutdown must receive a block" unless block_given?
|
|
97
91
|
|
|
98
92
|
@mutex.synchronize do
|
|
@@ -100,6 +94,7 @@ class ConnectionPool::TimedStack
|
|
|
100
94
|
@resource.broadcast
|
|
101
95
|
|
|
102
96
|
shutdown_connections
|
|
97
|
+
@shutdown_block = nil if reload
|
|
103
98
|
end
|
|
104
99
|
end
|
|
105
100
|
|
|
@@ -119,6 +114,10 @@ class ConnectionPool::TimedStack
|
|
|
119
114
|
|
|
120
115
|
private
|
|
121
116
|
|
|
117
|
+
def current_time
|
|
118
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
119
|
+
end
|
|
120
|
+
|
|
122
121
|
##
|
|
123
122
|
# This is an extension point for TimedStack and is called with a mutex.
|
|
124
123
|
#
|
|
@@ -147,6 +146,7 @@ class ConnectionPool::TimedStack
|
|
|
147
146
|
conn = fetch_connection(options)
|
|
148
147
|
@shutdown_block.call(conn)
|
|
149
148
|
end
|
|
149
|
+
@created = 0
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
##
|