async-pool 0.7.1 → 0.8.1

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: cfc00b6087965cc5fc3f58ae151a0048fc8cf351aab9c06bdaf46b0eb65bb877
4
- data.tar.gz: 7f9e3067d5bc75de995735ac4a025cb6cea4ee72e0e63201ec4f28c000301cc2
3
+ metadata.gz: 8d877fb908af8482011de394630982c4c593e36a5efd9ef19a885bba5774f6e8
4
+ data.tar.gz: be2d7efd8c65a9eec5237acc4f432e76a3f401da0b13e7e10b089f9849382f2a
5
5
  SHA512:
6
- metadata.gz: e6933852df812446375faf0c0c921c137bdd972beec9f1e392f6bdfc0c803ddf1cf62151323fbd18f8431c9ab1021eaac2c90ab461f03679d3e93cebfbc039b0
7
- data.tar.gz: 76a83cc5cc6a5dc2230ae6ad3eedc12a0e4fc24170d7391d5a1c032553d4a5653fc89b12060e331bd64687fefb5308d64785bbdc9cc70701b3f86e394de718f2
6
+ metadata.gz: 3e472af40018c10b2a8d726fc31b04ea96557d790c55e4fe6449a891b048c96da66794926eb7ca726195f778d0bea1e6c9d762b274a06a0922f382d5a8794ab7
7
+ data.tar.gz: 8abacfdcb4b32eb573e0108aecdbdd7ff385386e8a8de2710550b976a81467286e73fa8f36292162e801d5f000fc2a222aabf99f7cf334a35d7e22e47833ded1
checksums.yaml.gz.sig CHANGED
Binary file
@@ -11,6 +11,9 @@ require 'async'
11
11
  require 'async/notification'
12
12
  require 'async/semaphore'
13
13
 
14
+ require 'traces'
15
+ require 'metrics'
16
+
14
17
  module Async
15
18
  module Pool
16
19
  # A resource pool controller.
@@ -154,20 +157,20 @@ module Async
154
157
  retire(resource) unless processed
155
158
  end
156
159
 
157
- # Close all resources in the pool.
158
- def close
159
- @available.clear
160
+ def drain
161
+ Console.debug(self, "Draining pool...", size: @resources.size)
160
162
 
161
- while pair = @resources.shift
162
- resource, usage = pair
163
-
164
- if usage > 0
165
- Console.warn(self, resource: resource, usage: usage) {"Closing resource while still in use!"}
166
- end
167
-
168
- resource.close
163
+ # Enumerate all existing resources and retire them:
164
+ while resource = acquire_existing_resource
165
+ retire(resource)
169
166
  end
167
+ end
168
+
169
+ # Close all resources in the pool.
170
+ def close
171
+ self.drain
170
172
 
173
+ @available.clear
171
174
  @gardener&.stop
172
175
  end
173
176
 
@@ -224,6 +227,8 @@ module Async
224
227
  def start_gardener
225
228
  return if @gardener
226
229
 
230
+ @gardener = true
231
+
227
232
  Async(transient: true, annotation: "#{self.class} Gardener") do |task|
228
233
  @gardener = task
229
234
 
@@ -262,6 +267,7 @@ module Async
262
267
 
263
268
  def reuse(resource)
264
269
  Console.debug(self) {"Reuse #{resource}"}
270
+
265
271
  usage = @resources[resource]
266
272
 
267
273
  if usage.nil? || usage.zero?
@@ -286,11 +292,7 @@ module Async
286
292
  @notification.wait
287
293
  end
288
294
 
289
- Console.debug(self) {"Wait for resource -> #{resource}"}
290
-
291
- # if resource.concurrency > 1
292
- # @notification.signal
293
- # end
295
+ # Be careful not to context switch or fail here.
294
296
 
295
297
  return resource
296
298
  end
@@ -318,19 +320,40 @@ module Async
318
320
  def available_resource
319
321
  resource = nil
320
322
 
323
+ Console.debug(self, "Acquiring concurrency guard...", blocking: @guard.blocking?)
324
+
321
325
  @guard.acquire do
322
- resource = get_resource
326
+ Console.debug(self, "Acquired concurrency guard.")
327
+
328
+ resource = acquire_or_create_resource
323
329
  end
324
330
 
325
331
  return resource
326
- rescue Exception
332
+ rescue Exception => error
327
333
  reuse(resource) if resource
328
334
  raise
329
335
  end
330
336
 
331
337
  private
332
338
 
333
- def get_resource
339
+ # Acquire an existing resource with zero usage.
340
+ # If there are resources that are in use, wait until they are released.
341
+ def acquire_existing_resource
342
+ while @resources.any?
343
+ @resources.each do |resource, usage|
344
+ if usage == 0
345
+ return resource
346
+ end
347
+ end
348
+
349
+ @notification.wait
350
+ end
351
+
352
+ # Only when the pool has been completely drained, return nil:
353
+ return nil
354
+ end
355
+
356
+ def acquire_or_create_resource
334
357
  while resource = @available.last
335
358
  if usage = @resources[resource] and usage < resource.concurrency
336
359
  if resource.viable?
@@ -358,6 +381,50 @@ module Async
358
381
  return create_resource
359
382
  end
360
383
  end
384
+
385
+ Traces::Provider(self) do
386
+ def create_resource(...)
387
+ attributes = {
388
+ concurrency: @guard.limit,
389
+ size: @resources.size,
390
+ limit: @limit,
391
+ }
392
+
393
+ Traces.trace('async.pool.create', attributes: attributes) {super}
394
+ end
395
+
396
+ def drain(...)
397
+ attributes = {
398
+ size: @resources.size,
399
+ }
400
+
401
+ Traces.trace('async.pool.drain', attributes: attributes) {super}
402
+ end
403
+ end
404
+
405
+ Metrics::Provider(self) do
406
+ ACQUIRE_COUNT = Metrics.metric('async.pool.acquire', :counter, description: 'Number of times a resource was invoked.')
407
+ RELEASE_COUNT = Metrics.metric('async.pool.release', :counter, description: 'Number of times a resource was released.')
408
+ RETIRE_COUNT = Metrics.metric('async.pool.retire', :counter, description: 'Number of times a resource was retired.')
409
+
410
+ def acquire(...)
411
+ ACQUIRE_COUNT.emit(1)
412
+
413
+ super
414
+ end
415
+
416
+ def release(...)
417
+ super.tap do
418
+ RELEASE_COUNT.emit(1)
419
+ end
420
+ end
421
+
422
+ def retire(...)
423
+ super.tap do
424
+ RETIRE_COUNT.emit(1)
425
+ end
426
+ end
427
+ end
361
428
  end
362
429
  end
363
430
  end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Async
7
7
  module Pool
8
- VERSION = "0.7.1"
8
+ VERSION = "0.8.1"
9
9
  end
10
10
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -40,7 +40,7 @@ cert_chain:
40
40
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
41
41
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
42
42
  -----END CERTIFICATE-----
43
- date: 2024-08-03 00:00:00.000000000 Z
43
+ date: 2024-08-26 00:00:00.000000000 Z
44
44
  dependencies:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: async
@@ -56,6 +56,34 @@ dependencies:
56
56
  - - ">="
57
57
  - !ruby/object:Gem::Version
58
58
  version: '1.25'
59
+ - !ruby/object:Gem::Dependency
60
+ name: metrics
61
+ requirement: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ - !ruby/object:Gem::Dependency
74
+ name: traces
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ type: :runtime
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
59
87
  description:
60
88
  email:
61
89
  executables: []
metadata.gz.sig CHANGED
Binary file