connection_pool 2.4.1 → 2.5.0

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
2
  SHA256:
3
- metadata.gz: ea0776fcb09a3cc48ef4ca03774399e20b09e51039d0c47c1e4cb3bac621c52b
4
- data.tar.gz: b955d6b4e984259f20ae8cf6414f59692f9a51848424231363643e0c16dd2a3f
3
+ metadata.gz: 299b38ab20df15319b32d1a947b291137a5ab0f569d6ebf7153402f525f978c3
4
+ data.tar.gz: 300e5f15434761a80e388f5ff3a97e23d0a9d87d373e10703417231d6e14cf50
5
5
  SHA512:
6
- metadata.gz: bf57d8b5547502d91f5550ca6ea0be16905604c90e61efb6741e5ec3ce607c7a65f0b31e1673c96c60a06a2f64f5239cab6e94d3a50095fb822ea9b1c1bb2f0a
7
- data.tar.gz: 4b42aa5aa67b0e45bbbc8a9f29ca3a969efd8ade3b6dfca6cff082f526ec65a2a2e5c8fa17f512d33470b82535af8b675fc80903ccd75db26748e9845dd9a612
6
+ metadata.gz: 1ecdda6209d316a78ce8509514b4cb9676f5adae3cd07c95c75c9564b77a427d3c417e502aa32af65374f6aa63f8a5808b9ddf42d39ff89e9522adaf4c59dcd0
7
+ data.tar.gz: b1fb7ab8bc2cbcae36371268b03cdb59c4e25855cacd0d9588bfa012aea84801d4d879dff0a311492e89ba2584626029b85c1c3c9cf7efd51f8efb482c983f94
data/Changes.md CHANGED
@@ -1,5 +1,16 @@
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
+
3
14
  2.4.1
4
15
  ------
5
16
 
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
@@ -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.1"
2
+ VERSION = "2.5.0"
3
3
  end
@@ -160,6 +160,12 @@ class ConnectionPool
160
160
  @available.shutdown(reload: true, &block)
161
161
  end
162
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
+
163
169
  # Size of this connection pool
164
170
  attr_reader :size
165
171
  # Automatically drop all connections after fork
@@ -169,6 +175,11 @@ class ConnectionPool
169
175
  def available
170
176
  @available.length
171
177
  end
178
+
179
+ # Number of pool entries created and idle in the pool.
180
+ def idle
181
+ @available.idle
182
+ end
172
183
  end
173
184
 
174
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.1
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-05-19 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
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  - !ruby/object:Gem::Version
91
91
  version: '0'
92
92
  requirements: []
93
- rubygems_version: 3.4.7
93
+ rubygems_version: 3.5.22
94
94
  signing_key:
95
95
  specification_version: 4
96
96
  summary: Generic connection pool for Ruby