connection_pool 2.4.0 → 2.5.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
2
  SHA256:
3
- metadata.gz: e87682a6e57e8b0214de9c0713a7466a2b06399dc52d700fbf182cdf9e5b6606
4
- data.tar.gz: d12337513b62d4677663403c512afad165275bdf848987182ce03637a1de6482
3
+ metadata.gz: 299b38ab20df15319b32d1a947b291137a5ab0f569d6ebf7153402f525f978c3
4
+ data.tar.gz: 300e5f15434761a80e388f5ff3a97e23d0a9d87d373e10703417231d6e14cf50
5
5
  SHA512:
6
- metadata.gz: eca2c1f8ebe52039f00df70ddfe5525cc0408acd8ae9849a8d1412bec670e7d3a05d3609db933e3e906cd83307d39f754dd5f1d7b48b50b847090b5bf485b55a
7
- data.tar.gz: fc9a62b4b0ba5a406543e8f6399bd566f2f31c6c9a6ce2772e3550c1c2a75945c8a34defeda10c83e23cbfe5fe50d0e8861f57ea23935d7c97540aa97b04a635
6
+ metadata.gz: 1ecdda6209d316a78ce8509514b4cb9676f5adae3cd07c95c75c9564b77a427d3c417e502aa32af65374f6aa63f8a5808b9ddf42d39ff89e9522adaf4c59dcd0
7
+ data.tar.gz: b1fb7ab8bc2cbcae36371268b03cdb59c4e25855cacd0d9588bfa012aea84801d4d879dff0a311492e89ba2584626029b85c1c3c9cf7efd51f8efb482c983f94
data/Changes.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # connection_pool Changelog
2
2
 
3
+ 2.5.0
4
+ ------
5
+
6
+ - Reap idle connections [#187]
7
+ ```ruby
8
+ idle_timeout = 60
9
+ pool = ConnectionPool.new ...
10
+ pool.reap(idle_timeout, &:close)
11
+ ```
12
+ - `ConnectionPool#idle` returns the count of connections not in use [#187]
13
+
14
+ 2.4.1
15
+ ------
16
+
17
+ - New `auto_reload_after_fork` config option to disable auto-drop [#177, shayonj]
18
+
3
19
  2.4.0
4
20
  ------
5
21
 
data/README.md CHANGED
@@ -101,6 +101,34 @@ cp.with { |conn| conn.get('some-count') }
101
101
 
102
102
  Like `shutdown`, this will block until all connections are checked in and closed.
103
103
 
104
+ ## Reap
105
+
106
+ You can reap idle connections in the ConnectionPool instance to close connections that were created but have not been used for a certain amount of time. This can be useful to run periodically in a separate thread especially if keeping the connection open is resource intensive.
107
+
108
+ You can specify how many seconds the connections have to be idle for them to be reaped.
109
+ Defaults to 60 seconds.
110
+
111
+ ```ruby
112
+ cp = ConnectionPool.new { Redis.new }
113
+ cp.reap(300) { |conn| conn.close } # Reaps connections that have been idle for 300 seconds (5 minutes).
114
+ ```
115
+
116
+ ### Reaper Thread
117
+
118
+ You can start your own reaper thread to reap idle connections in the ConnectionPool instance on a regular interval.
119
+
120
+ ```ruby
121
+ cp = ConnectionPool.new { Redis.new }
122
+
123
+ # Start a reaper thread to reap connections that have been idle for 300 seconds (5 minutes).
124
+ Thread.new do
125
+ loop do
126
+ cp.reap(300) { |conn| conn.close }
127
+ sleep 300
128
+ end
129
+ end
130
+ ```
131
+
104
132
  ## Current State
105
133
 
106
134
  There are several methods that return information about a pool.
@@ -109,11 +137,15 @@ There are several methods that return information about a pool.
109
137
  cp = ConnectionPool.new(size: 10) { Redis.new }
110
138
  cp.size # => 10
111
139
  cp.available # => 10
140
+ cp.idle # => 0
112
141
 
113
142
  cp.with do |conn|
114
143
  cp.size # => 10
115
144
  cp.available # => 9
145
+ cp.idle # => 0
116
146
  end
147
+
148
+ cp.idle # => 1
117
149
  ```
118
150
 
119
151
  Notes
@@ -19,4 +19,6 @@ Gem::Specification.new do |s|
19
19
  s.add_development_dependency "minitest", ">= 5.0.0"
20
20
  s.add_development_dependency "rake"
21
21
  s.required_ruby_version = ">= 2.5.0"
22
+
23
+ s.metadata = {"changelog_uri" => "https://github.com/mperham/connection_pool/blob/main/Changes.md", "rubygems_mfa_required" => "true"}
22
24
  end
@@ -41,6 +41,7 @@ class ConnectionPool::TimedStack
41
41
  def push(obj, options = {})
42
42
  @mutex.synchronize do
43
43
  if @shutdown_block
44
+ @created -= 1 unless @created == 0
44
45
  @shutdown_block.call(obj)
45
46
  else
46
47
  store_connection obj, options
@@ -98,6 +99,26 @@ class ConnectionPool::TimedStack
98
99
  end
99
100
  end
100
101
 
102
+ ##
103
+ # Reaps connections that were checked in more than +idle_seconds+ ago.
104
+ def reap(idle_seconds, &block)
105
+ raise ArgumentError, "reap must receive a block" unless block
106
+ raise ArgumentError, "idle_seconds must be a number" unless idle_seconds.is_a?(Numeric)
107
+ raise ConnectionPool::PoolShuttingDownError if @shutdown_block
108
+
109
+ idle.times do
110
+ conn =
111
+ @mutex.synchronize do
112
+ raise ConnectionPool::PoolShuttingDownError if @shutdown_block
113
+
114
+ reserve_idle_connection(idle_seconds)
115
+ end
116
+ break unless conn
117
+
118
+ block.call(conn)
119
+ end
120
+ end
121
+
101
122
  ##
102
123
  # Returns +true+ if there are no available connections.
103
124
 
@@ -112,6 +133,12 @@ class ConnectionPool::TimedStack
112
133
  @max - @created + @que.length
113
134
  end
114
135
 
136
+ ##
137
+ # The number of connections created and available on the stack.
138
+ def idle
139
+ @que.length
140
+ end
141
+
115
142
  private
116
143
 
117
144
  def current_time
@@ -133,7 +160,7 @@ class ConnectionPool::TimedStack
133
160
  # This method must return a connection from the stack.
134
161
 
135
162
  def fetch_connection(options = nil)
136
- @que.pop
163
+ @que.pop&.first
137
164
  end
138
165
 
139
166
  ##
@@ -144,9 +171,32 @@ class ConnectionPool::TimedStack
144
171
  def shutdown_connections(options = nil)
145
172
  while connection_stored?(options)
146
173
  conn = fetch_connection(options)
174
+ @created -= 1 unless @created == 0
147
175
  @shutdown_block.call(conn)
148
176
  end
149
- @created = 0
177
+ end
178
+
179
+ ##
180
+ # This is an extension point for TimedStack and is called with a mutex.
181
+ #
182
+ # This method returns the oldest idle connection if it has been idle for more than idle_seconds.
183
+ # This requires that the stack is kept in order of checked in time (oldest first).
184
+
185
+ def reserve_idle_connection(idle_seconds)
186
+ return unless idle_connections?(idle_seconds)
187
+
188
+ @created -= 1 unless @created == 0
189
+
190
+ @que.shift.first
191
+ end
192
+
193
+ ##
194
+ # This is an extension point for TimedStack and is called with a mutex.
195
+ #
196
+ # Returns true if the first connection in the stack has been idle for more than idle_seconds
197
+
198
+ def idle_connections?(idle_seconds)
199
+ connection_stored? && (current_time - @que.first.last > idle_seconds)
150
200
  end
151
201
 
152
202
  ##
@@ -155,7 +205,7 @@ class ConnectionPool::TimedStack
155
205
  # This method must return +obj+ to the stack.
156
206
 
157
207
  def store_connection(obj, options = nil)
158
- @que.push obj
208
+ @que.push [obj, current_time]
159
209
  end
160
210
 
161
211
  ##
@@ -1,3 +1,3 @@
1
1
  class ConnectionPool
2
- VERSION = "2.4.0"
2
+ VERSION = "2.5.0"
3
3
  end
@@ -36,9 +36,10 @@ end
36
36
  # Accepts the following options:
37
37
  # - :size - number of connections to pool, defaults to 5
38
38
  # - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds
39
+ # - :auto_reload_after_fork - automatically drop all connections after fork, defaults to true
39
40
  #
40
41
  class ConnectionPool
41
- DEFAULTS = {size: 5, timeout: 5}
42
+ DEFAULTS = {size: 5, timeout: 5, auto_reload_after_fork: true}
42
43
 
43
44
  def self.wrap(options, &block)
44
45
  Wrapper.new(options, &block)
@@ -50,11 +51,12 @@ class ConnectionPool
50
51
 
51
52
  def self.after_fork
52
53
  INSTANCES.values.each do |pool|
54
+ next unless pool.auto_reload_after_fork
55
+
53
56
  # We're on after fork, so we know all other threads are dead.
54
57
  # All we need to do is to ensure the main thread doesn't have a
55
58
  # checked out connection
56
59
  pool.checkin(force: true)
57
-
58
60
  pool.reload do |connection|
59
61
  # Unfortunately we don't know what method to call to close the connection,
60
62
  # so we try the most common one.
@@ -92,6 +94,7 @@ class ConnectionPool
92
94
 
93
95
  @size = Integer(options.fetch(:size))
94
96
  @timeout = options.fetch(:timeout)
97
+ @auto_reload_after_fork = options.fetch(:auto_reload_after_fork)
95
98
 
96
99
  @available = TimedStack.new(@size, &block)
97
100
  @key = :"pool-#{@available.object_id}"
@@ -157,13 +160,26 @@ class ConnectionPool
157
160
  @available.shutdown(reload: true, &block)
158
161
  end
159
162
 
163
+ ## Reaps idle connections that have been idle for over +idle_seconds+.
164
+ # +idle_seconds+ defaults to 60.
165
+ def reap(idle_seconds = 60, &block)
166
+ @available.reap(idle_seconds, &block)
167
+ end
168
+
160
169
  # Size of this connection pool
161
170
  attr_reader :size
171
+ # Automatically drop all connections after fork
172
+ attr_reader :auto_reload_after_fork
162
173
 
163
174
  # Number of pool entries available for checkout at this instant.
164
175
  def available
165
176
  @available.length
166
177
  end
178
+
179
+ # Number of pool entries created and idle in the pool.
180
+ def idle
181
+ @available.idle
182
+ end
167
183
  end
168
184
 
169
185
  require_relative "connection_pool/timed_stack"
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.0
4
+ version: 2.5.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: 2023-03-24 00:00:00.000000000 Z
12
+ date: 2025-01-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -72,7 +72,9 @@ files:
72
72
  homepage: https://github.com/mperham/connection_pool
73
73
  licenses:
74
74
  - MIT
75
- metadata: {}
75
+ metadata:
76
+ changelog_uri: https://github.com/mperham/connection_pool/blob/main/Changes.md
77
+ rubygems_mfa_required: 'true'
76
78
  post_install_message:
77
79
  rdoc_options: []
78
80
  require_paths:
@@ -88,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
90
  - !ruby/object:Gem::Version
89
91
  version: '0'
90
92
  requirements: []
91
- rubygems_version: 3.4.7
93
+ rubygems_version: 3.5.22
92
94
  signing_key:
93
95
  specification_version: 4
94
96
  summary: Generic connection pool for Ruby