async-pool 0.3.2 → 0.3.7
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 +4 -4
- data/lib/async/pool/controller.rb +97 -25
- data/lib/async/pool/resource.rb +1 -1
- data/lib/async/pool/version.rb +1 -1
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36dfa0c90392d3f6e3582b1bdd3e2fdb7667ddccb601fb4dd34df3e8aa3baa2e
|
4
|
+
data.tar.gz: bea9381873eed77a2fd9dcb4d90190e9fa3ebbbba0f38c5628ee369f5da58a97
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ece710c9d7ec8fcb62b92ae9fb19775de4f781f886a3b9e285f08a0a9483599bc15e6b5d727df7697202f1b11381cba5ebb731d84ad9236abc4c29d8293a508
|
7
|
+
data.tar.gz: 02d545782a0b63b7ba74ce19a450ab7851886548eb71805c2fd9e5b71f8daf838c5dfbd5013b6bec2b639a2f630a5dfc846baaf9b28581cf53cb26d9b975290d
|
@@ -18,7 +18,7 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
require '
|
21
|
+
require 'console/logger'
|
22
22
|
|
23
23
|
require 'async'
|
24
24
|
require 'async/notification'
|
@@ -32,9 +32,13 @@ module Async
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def initialize(constructor, limit: nil)
|
35
|
+
# All available resources:
|
35
36
|
@resources = {}
|
36
37
|
|
38
|
+
# Resources which may be available to be acquired:
|
39
|
+
# This list may contain false positives, or resources which were okay but have since entered a state which is unusuable.
|
37
40
|
@available = []
|
41
|
+
|
38
42
|
@notification = Async::Notification.new
|
39
43
|
|
40
44
|
@limit = limit
|
@@ -45,7 +49,7 @@ module Async
|
|
45
49
|
@gardener = nil
|
46
50
|
end
|
47
51
|
|
48
|
-
# @
|
52
|
+
# @attribute [Hash(Resource, Integer)] all allocated resources, and their associated usage.
|
49
53
|
attr :resources
|
50
54
|
|
51
55
|
def size
|
@@ -66,6 +70,11 @@ module Async
|
|
66
70
|
return false
|
67
71
|
end
|
68
72
|
|
73
|
+
# Whether there are available resources, i.e. whether {#acquire} can reuse an existing resource.
|
74
|
+
def available?
|
75
|
+
@available.any?
|
76
|
+
end
|
77
|
+
|
69
78
|
# Wait until a pool resource has been freed.
|
70
79
|
def wait
|
71
80
|
@notification.wait
|
@@ -98,6 +107,8 @@ module Async
|
|
98
107
|
end
|
99
108
|
|
100
109
|
def close
|
110
|
+
@available.clear
|
111
|
+
|
101
112
|
@resources.each_key(&:close)
|
102
113
|
@resources.clear
|
103
114
|
|
@@ -119,7 +130,9 @@ module Async
|
|
119
130
|
unused = []
|
120
131
|
|
121
132
|
@resources.each do |resource, usage|
|
122
|
-
|
133
|
+
if usage.zero?
|
134
|
+
unused << resource
|
135
|
+
end
|
123
136
|
end
|
124
137
|
|
125
138
|
unused.each do |resource|
|
@@ -132,11 +145,19 @@ module Async
|
|
132
145
|
break if @resources.size <= retain
|
133
146
|
end
|
134
147
|
|
148
|
+
# Update availability list:
|
149
|
+
@available.clear
|
150
|
+
@resources.each do |resource, usage|
|
151
|
+
if usage < resource.concurrency and resource.reusable?
|
152
|
+
@available << resource
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
135
156
|
return unused.size
|
136
157
|
end
|
137
158
|
|
138
159
|
def retire(resource)
|
139
|
-
|
160
|
+
Console.logger.debug(self) {"Retire #{resource}"}
|
140
161
|
|
141
162
|
@resources.delete(resource)
|
142
163
|
|
@@ -150,7 +171,7 @@ module Async
|
|
150
171
|
def start_gardener
|
151
172
|
return if @gardener
|
152
173
|
|
153
|
-
Async(transient: true) do |task|
|
174
|
+
Async(transient: true, annotation: "#{self.class} Gardener") do |task|
|
154
175
|
@gardener = task
|
155
176
|
|
156
177
|
Task.yield
|
@@ -170,11 +191,42 @@ module Async
|
|
170
191
|
end.join(";")
|
171
192
|
end
|
172
193
|
|
194
|
+
def usage
|
195
|
+
@resources.count{|resource, usage| usage > 0}
|
196
|
+
end
|
197
|
+
|
198
|
+
def free
|
199
|
+
@resources.count{|resource, usage| usage == 0}
|
200
|
+
end
|
201
|
+
|
202
|
+
# @returns [Boolean] Whether the number of available resources is excessive and we should retire some.
|
203
|
+
def overflowing?
|
204
|
+
if @resources.any?
|
205
|
+
(self.free.to_f / @resources.size) > 0.5
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
173
209
|
def reuse(resource)
|
174
|
-
|
210
|
+
Console.logger.debug(self) {"Reuse #{resource}"}
|
211
|
+
usage = @resources[resource]
|
175
212
|
|
176
|
-
|
177
|
-
|
213
|
+
if usage.zero?
|
214
|
+
raise "Trying to reuse unacquired resource: #{resource}!"
|
215
|
+
end
|
216
|
+
|
217
|
+
# We retire resources when adding to the @available list would overflow our pool:
|
218
|
+
if usage == 1
|
219
|
+
if overflowing?
|
220
|
+
return retire(resource)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# If the resource was fully utilized, it now becomes available:
|
225
|
+
if usage == resource.concurrency
|
226
|
+
@available.push(resource)
|
227
|
+
end
|
228
|
+
|
229
|
+
@resources[resource] = usage - 1
|
178
230
|
|
179
231
|
@notification.signal
|
180
232
|
end
|
@@ -185,7 +237,7 @@ module Async
|
|
185
237
|
@notification.wait
|
186
238
|
end
|
187
239
|
|
188
|
-
|
240
|
+
Console.logger.debug(self) {"Wait for resource -> #{resource}"}
|
189
241
|
|
190
242
|
# if resource.concurrency > 1
|
191
243
|
# @notification.signal
|
@@ -194,6 +246,7 @@ module Async
|
|
194
246
|
return resource
|
195
247
|
end
|
196
248
|
|
249
|
+
# @returns [Object] A new resource in a "used" state.
|
197
250
|
def create_resource
|
198
251
|
self.start_gardener
|
199
252
|
|
@@ -201,37 +254,56 @@ module Async
|
|
201
254
|
if resource = @constructor.call
|
202
255
|
@resources[resource] = 1
|
203
256
|
|
204
|
-
|
257
|
+
# Make the resource available if it can be used multiple times:
|
258
|
+
if resource.concurrency > 1
|
259
|
+
@available.push(resource)
|
260
|
+
end
|
205
261
|
end
|
206
262
|
|
207
263
|
return resource
|
208
264
|
end
|
209
265
|
|
266
|
+
# @returns [Object] An existing resource in a "used" state.
|
210
267
|
def available_resource
|
268
|
+
resource = nil
|
269
|
+
|
211
270
|
@guard.acquire do
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
271
|
+
resource = get_resource
|
272
|
+
end
|
273
|
+
|
274
|
+
return resource
|
275
|
+
rescue Exception
|
276
|
+
reuse(resource) if resource
|
277
|
+
raise
|
278
|
+
end
|
279
|
+
|
280
|
+
private def get_resource
|
281
|
+
while resource = @available.last
|
282
|
+
if usage = @resources[resource] and usage < resource.concurrency
|
283
|
+
if resource.viable?
|
284
|
+
usage = (@resources[resource] += 1)
|
285
|
+
|
286
|
+
if usage == resource.concurrency
|
287
|
+
# The resource is used up to it's limit:
|
220
288
|
@available.pop
|
221
289
|
end
|
290
|
+
|
291
|
+
return resource
|
222
292
|
else
|
293
|
+
retire(resource)
|
223
294
|
@available.pop
|
224
295
|
end
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
Async.logger.debug(self) {"No resources resources, allocating new one..."}
|
229
|
-
|
230
|
-
return create_resource
|
296
|
+
else
|
297
|
+
# The resource has been removed already, so skip it and remove it from the availability list.
|
298
|
+
@available.pop
|
231
299
|
end
|
232
300
|
end
|
233
301
|
|
234
|
-
|
302
|
+
if @limit.nil? or @resources.size < @limit
|
303
|
+
Console.logger.debug(self) {"No available resources, allocating new one..."}
|
304
|
+
|
305
|
+
return create_resource
|
306
|
+
end
|
235
307
|
end
|
236
308
|
end
|
237
309
|
end
|
data/lib/async/pool/resource.rb
CHANGED
data/lib/async/pool/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-pool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|
@@ -108,8 +108,8 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '3.6'
|
111
|
-
description:
|
112
|
-
email:
|
111
|
+
description:
|
112
|
+
email:
|
113
113
|
executables: []
|
114
114
|
extensions: []
|
115
115
|
extra_rdoc_files: []
|
@@ -123,7 +123,7 @@ licenses:
|
|
123
123
|
- MIT
|
124
124
|
metadata:
|
125
125
|
funding_uri: https://github.com/sponsors/ioquatix/
|
126
|
-
post_install_message:
|
126
|
+
post_install_message:
|
127
127
|
rdoc_options: []
|
128
128
|
require_paths:
|
129
129
|
- lib
|
@@ -131,15 +131,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
131
|
requirements:
|
132
132
|
- - ">="
|
133
133
|
- !ruby/object:Gem::Version
|
134
|
-
version: '
|
134
|
+
version: '2.5'
|
135
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
136
|
requirements:
|
137
137
|
- - ">="
|
138
138
|
- !ruby/object:Gem::Version
|
139
139
|
version: '0'
|
140
140
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
142
|
-
signing_key:
|
141
|
+
rubygems_version: 3.3.0.dev
|
142
|
+
signing_key:
|
143
143
|
specification_version: 4
|
144
144
|
summary: A singleplex and multiplex resource pool for implementing robust clients.
|
145
145
|
test_files: []
|