async-limiter 2.0.0 → 2.2.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: 324fe64138f3bd6854bc8d5349b8404a01d6bd11ee64f5b0ad204d4154efa15b
4
- data.tar.gz: 4cc2963430befada104733f236d4e59b900750c1e3eeeb73fc18f2dece26c5b2
3
+ metadata.gz: d153319af347142e9837f3a8e7523f47f2bbd28d56e497d03c0fd7279302af8f
4
+ data.tar.gz: 9d1da2a75240ba77a68d26141abf50b677d5248b9bf191a50e8821aac3bceee7
5
5
  SHA512:
6
- metadata.gz: 815670fb97ad80d90e9a5a6ec9034f51242fe793784220af2b3ce769b3afd49389a03a0d53ac042aa98638affef8636607976f6908f834e667ab31ac96fbb628
7
- data.tar.gz: 5f8df98d26156a041023d05e9c758a17eeefca437cd9ffa34c9a102df820a3e45380dbda8e09b23dd14e189014a49554745349ff13de70647d59a7a5abe33d4d
6
+ metadata.gz: a35d89989f3d8faf3cd203a84b2e04125809ae07d6609ce0dc205214f97bc1bf11ab099bbc46542a3fa701674185e641461d548f67bb1d1325b8badce9b6c6cc
7
+ data.tar.gz: df563bd337ae1e9157df61f0b47ae35d1e536b15ad5c0e7cb6fe7ebf48f32bf18249185307aa07d287c3c54df90f8463ce014531763536bd8f92428c0d13e0f9
checksums.yaml.gz.sig CHANGED
Binary file
@@ -35,7 +35,7 @@ require "async/limiter"
35
35
 
36
36
  Async do
37
37
  limiter = Async::Limiter::Generic.new
38
-
38
+
39
39
  # Create async tasks through the limiter:
40
40
  tasks = 5.times.map do |i|
41
41
  limiter.async do |task|
@@ -81,7 +81,7 @@ Async do
81
81
  # Allow unlimited concurrency but rate limit to 10 operations per second:
82
82
  timing = Async::Limiter::Timing::LeakyBucket.new(10.0, 50.0)
83
83
  limiter = Async::Limiter::Generic.new(timing: timing)
84
-
84
+
85
85
  # All tasks start immediately, but timing strategy controls rate:
86
86
  100.times do |i|
87
87
  limiter.async do |task|
@@ -86,7 +86,7 @@ Async do
86
86
 
87
87
  limiter.acquire(timeout: 3)
88
88
  # => nil
89
-
89
+
90
90
  limiter.acquire(timeout: 3) do
91
91
  puts "Acquired."
92
92
  end or puts "Timed out!"
@@ -199,8 +199,8 @@ fair_limiter.acquire(cost: 8.0) do
199
199
  end
200
200
 
201
201
  # These must wait even though they need fewer tokens
202
- fair_limiter.acquire(cost: 0.5) { puts "Quick op 1" } # Blocked
203
- fair_limiter.acquire(cost: 0.5) { puts "Quick op 2" } # Blocked
202
+ fair_limiter.acquire(cost: 0.5){puts "Quick op 1"} # Blocked
203
+ fair_limiter.acquire(cost: 0.5){puts "Quick op 2"} # Blocked
204
204
  ```
205
205
 
206
206
  #### Choosing the Right Strategy
@@ -89,16 +89,16 @@ The limiter prevents convoy effects where quick timeouts aren't blocked by slow
89
89
  limiter = Async::Limiter::Limited.new(1)
90
90
  Async do
91
91
  limiter.acquire # Fill to capacity.
92
-
92
+
93
93
  results = []
94
-
94
+
95
95
  # Start multiple tasks with different timeouts:
96
96
  tasks = [
97
- Async {limiter.acquire(timeout: 1.0); results << "Long timeout."},
98
- Async {limiter.acquire(timeout: 0.1); results << "Short timeout."},
99
- Async {limiter.acquire(timeout: 0); results << "Non-blocking."},
97
+ Async{limiter.acquire(timeout: 1.0); results << "Long timeout."},
98
+ Async{limiter.acquire(timeout: 0.1); results << "Short timeout."},
99
+ Async{limiter.acquire(timeout: 0); results << "Non-blocking."},
100
100
  ]
101
-
101
+
102
102
  # All tasks complete quickly, even with a long timeout task present:
103
103
  tasks.map(&:wait)
104
104
  puts results
@@ -42,7 +42,7 @@ For fine-grained control over resource lifecycle:
42
42
 
43
43
  ```ruby
44
44
  queue = Async::Queue.new
45
- 3.times { |i| queue.push("resource_#{i}") }
45
+ 3.times{|i| queue.push("resource_#{i}")}
46
46
 
47
47
  limiter = Async::Limiter::Queued.new(queue)
48
48
 
@@ -71,7 +71,7 @@ Async do
71
71
  queue = Async::PriorityQueue.new
72
72
  limiter = Async::Limiter::Queued.new(queue)
73
73
  results = []
74
-
74
+
75
75
  # Start tasks with different priorities
76
76
  tasks = [
77
77
  Async do
@@ -100,9 +100,9 @@ Async do
100
100
  2.times do |i|
101
101
  limiter.release("worker_#{i}")
102
102
  end
103
-
103
+
104
104
  tasks.each(&:wait)
105
-
105
+
106
106
  puts results
107
107
  # High priority task gets resource first, then medium, then low.
108
108
  end
@@ -385,7 +385,7 @@ require "async/queue"
385
385
 
386
386
  # Create resource queue
387
387
  queue = Async::Queue.new
388
- 3.times { |i| queue.push("worker_#{i}") }
388
+ 3.times{|i| queue.push("worker_#{i}")}
389
389
 
390
390
  # Add timing constraint
391
391
  timing = Async::Limiter::Timing::FixedWindow.new(2.0,
@@ -437,8 +437,8 @@ class RateLimitedAPIClient
437
437
 
438
438
  def make_request(endpoint, cost: 1.0)
439
439
  @limiter.acquire(cost: cost) do
440
- # Make actual HTTP request:
441
- puts "Making request to #{endpoint} at #{Time.now}"
440
+ # Make actual HTTP request:
441
+ puts "Making request to #{endpoint} at #{Time.now}"
442
442
  simulate_http_request(endpoint)
443
443
  end
444
444
  end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2025, by Shopify Inc.
4
+ # Copyright, 2025-2026, by Shopify Inc.
5
5
  # Copyright, 2025, by Samuel Williams.
6
6
 
7
7
  require "async/task"
8
8
  require "async/deadline"
9
+ require "async/utilization"
10
+ require "json"
9
11
  require_relative "timing/none"
10
12
  require_relative "timing/sliding_window"
11
13
  require_relative "token"
@@ -23,10 +25,12 @@ module Async
23
25
  # Initialize a new generic limiter.
24
26
  # @parameter timing [#acquire, #wait, #maximum_cost] Strategy for timing constraints.
25
27
  # @parameter parent [Async::Task, nil] Parent task for creating child tasks.
26
- def initialize(timing: Timing::None, parent: nil, tags: nil)
28
+ # @parameter utilization [#metric] Registry-like object for utilization metrics.
29
+ def initialize(timing: Timing::None, parent: nil, tags: nil, utilization: Async::Utilization::Registry.new)
27
30
  @timing = timing
28
31
  @parent = parent
29
32
  @tags = tags
33
+ @utilization = utilization
30
34
 
31
35
  @mutex = Mutex.new
32
36
  end
@@ -34,6 +38,9 @@ module Async
34
38
  # @attribute [Array(String)] Tags associated with this limiter for identification or categorization.
35
39
  attr :tags
36
40
 
41
+ # @attribute [#metric] Registry-like object for utilization metrics.
42
+ attr :utilization
43
+
37
44
  # @returns [Boolean] Whether this limiter is currently limiting concurrency.
38
45
  def limited?
39
46
  false
@@ -66,7 +73,7 @@ module Async
66
73
  end
67
74
 
68
75
  # Manually acquire a resource with timing and concurrency coordination.
69
- #
76
+ #
70
77
  # This method provides the core acquisition logic with support for:
71
78
  # - Flexible timeout handling (blocking, non-blocking, timed)
72
79
  # - Cost-based consumption for timing strategies
@@ -135,6 +142,18 @@ module Async
135
142
  end
136
143
  end
137
144
 
145
+ # Get a JSON-compatible representation of the limiter statistics.
146
+ # @returns [Hash] Statistics hash with current state.
147
+ def as_json(...)
148
+ statistics
149
+ end
150
+
151
+ # Get a JSON string representation of the limiter statistics.
152
+ # @returns [String] JSON encoded statistics.
153
+ def to_json(...)
154
+ as_json.to_json(...)
155
+ end
156
+
138
157
  protected
139
158
 
140
159
  def acquire_synchronized(timeout, cost, **options)
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020, by Bruno Sutic.
5
- # Copyright, 2025, by Shopify Inc.
5
+ # Copyright, 2025-2026, by Shopify Inc.
6
6
  # Copyright, 2025, by Samuel Williams.
7
7
 
8
8
  require_relative "generic"
@@ -20,16 +20,22 @@ module Async
20
20
  class Limited < Generic
21
21
  # Initialize a limited concurrency limiter.
22
22
  # @parameter limit [Integer] Maximum concurrent tasks allowed.
23
- # @parameter timing [#acquire, #wait, #maximum_cost] Strategy for timing constraints.
24
- # @parameter parent [Async::Task, nil] Parent task for creating child tasks.
23
+ # @parameter options [Hash] Options passed to {Generic#initialize}.
25
24
  # @raises [ArgumentError] If limit is not positive.
26
- def initialize(limit = 1, timing: Timing::None, parent: nil)
27
- super(timing: timing, parent: parent)
25
+ def initialize(limit = 1, **options)
26
+ super(**options)
28
27
 
29
28
  @limit = limit
30
29
  @count = 0
31
30
 
32
31
  @available = ConditionVariable.new
32
+
33
+ @acquired_count_metric = @utilization.metric(:acquired_count)
34
+ @available_count_metric = @utilization.metric(:available_count)
35
+ @waiting_count_metric = @utilization.metric(:waiting_count)
36
+ @reacquire_waiting_count_metric = @utilization.metric(:reacquire_waiting_count)
37
+
38
+ update_utilization_metrics
33
39
  end
34
40
 
35
41
  # @attribute [Integer] The maximum number of concurrent tasks.
@@ -38,6 +44,26 @@ module Async
38
44
  # @attribute [Integer] Current count of active tasks.
39
45
  attr_reader :count
40
46
 
47
+ # @returns [Integer] Current count of active tasks.
48
+ def acquired_count
49
+ @mutex.synchronize{@count}
50
+ end
51
+
52
+ # @returns [Integer] Current count of available capacity.
53
+ def available_count
54
+ @mutex.synchronize{@limit - @count}
55
+ end
56
+
57
+ # @returns [Integer] Current count of tasks waiting for capacity.
58
+ def waiting_count
59
+ @waiting_count_metric.value
60
+ end
61
+
62
+ # @returns [Integer] Current count of reacquiring tasks waiting for capacity.
63
+ def reacquire_waiting_count
64
+ @reacquire_waiting_count_metric.value
65
+ end
66
+
41
67
  # Check if a new task can be acquired.
42
68
  # @returns [Boolean] True if under the limit.
43
69
  def limited?
@@ -51,6 +77,7 @@ module Async
51
77
  @mutex.synchronize do
52
78
  old_limit = @limit
53
79
  @limit = new_limit
80
+ update_utilization_metrics
54
81
 
55
82
  # Wake up waiting tasks if limit increased:
56
83
  @available.broadcast if new_limit > old_limit
@@ -64,6 +91,10 @@ module Async
64
91
  {
65
92
  limit: @limit,
66
93
  count: @count,
94
+ acquired_count: @count,
95
+ available_count: @limit - @count,
96
+ waiting_count: @waiting_count_metric.value,
97
+ reacquire_waiting_count: @reacquire_waiting_count_metric.value,
67
98
  timing: @timing.statistics
68
99
  }
69
100
  end
@@ -72,32 +103,57 @@ module Async
72
103
  protected
73
104
 
74
105
  # Acquire resource with optional deadline.
75
- def acquire_resource(deadline, **options)
106
+ def acquire_resource(deadline, reacquire: false, **options)
76
107
  # Fast path: immediate return for expired deadlines, but only if at capacity
77
108
  return nil if deadline&.expired? && @count >= @limit
78
109
 
110
+ waiting = false
111
+ acquired = false
112
+
79
113
  # Wait for capacity with deadline tracking
80
114
  while @count >= @limit
81
115
  remaining = deadline&.remaining
82
116
  return nil if remaining && remaining <= 0
83
117
 
118
+ unless waiting
119
+ @waiting_count_metric.increment
120
+ @reacquire_waiting_count_metric.increment if reacquire
121
+ waiting = true
122
+ end
123
+
84
124
  unless @available.wait(@mutex, remaining)
85
125
  return nil # Timeout exceeded
86
126
  end
87
127
  end
88
128
 
89
129
  @count += 1
130
+ acquired = true
90
131
 
91
132
  return true
133
+ ensure
134
+ if waiting
135
+ @waiting_count_metric.decrement
136
+ @reacquire_waiting_count_metric.decrement if reacquire
137
+ end
138
+
139
+ update_utilization_metrics if acquired
92
140
  end
93
141
 
94
142
  # Release resource.
95
143
  def release_resource(resource)
96
144
  @mutex.synchronize do
97
145
  @count -= 1
146
+ update_utilization_metrics
98
147
  @available.signal
99
148
  end
100
149
  end
150
+
151
+ private
152
+
153
+ def update_utilization_metrics
154
+ @acquired_count_metric.set(@count)
155
+ @available_count_metric.set(@limit - @count)
156
+ end
101
157
  end
102
158
  end
103
159
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2025, by Francisco Mejia.
5
- # Copyright, 2025, by Shopify Inc.
5
+ # Copyright, 2025-2026, by Shopify Inc.
6
6
  # Copyright, 2025, by Samuel Williams.
7
7
 
8
8
  require_relative "generic"
@@ -28,16 +28,42 @@ module Async
28
28
 
29
29
  # Initialize a queue-based limiter.
30
30
  # @parameter queue [#push, #pop, #empty?] Thread-safe queue containing pre-existing resources.
31
- # @parameter timing [#acquire, #wait, #maximum_cost] Strategy for timing constraints.
32
- # @parameter parent [Async::Task, nil] Parent task for creating child tasks.
33
- def initialize(queue = self.class.default_queue, timing: Timing::None, parent: nil)
34
- super(timing: timing, parent: parent)
31
+ # @parameter options [Hash] Options passed to {Generic#initialize}.
32
+ def initialize(queue = self.class.default_queue, **options)
33
+ super(**options)
35
34
  @queue = queue
35
+
36
+ @acquired_count_metric = @utilization.metric(:acquired_count)
37
+ @available_count_metric = @utilization.metric(:available_count)
38
+ @waiting_count_metric = @utilization.metric(:waiting_count)
39
+ @reacquire_waiting_count_metric = @utilization.metric(:reacquire_waiting_count)
40
+
41
+ update_utilization_metrics
36
42
  end
37
43
 
38
44
  # @attribute [Queue] The queue managing resources.
39
45
  attr_reader :queue
40
46
 
47
+ # @returns [Integer] Current count of acquired resources.
48
+ def acquired_count
49
+ @acquired_count_metric.value
50
+ end
51
+
52
+ # @returns [Integer] Current count of available resources.
53
+ def available_count
54
+ @queue.size
55
+ end
56
+
57
+ # @returns [Integer] Current count of tasks waiting for resources.
58
+ def waiting_count
59
+ @queue.waiting_count
60
+ end
61
+
62
+ # @returns [Integer] Current count of reacquiring tasks waiting for resources.
63
+ def reacquire_waiting_count
64
+ @reacquire_waiting_count_metric.value
65
+ end
66
+
41
67
  # Check if a new task can be acquired.
42
68
  # @returns [Boolean] True if resources are available.
43
69
  def limited?
@@ -51,6 +77,8 @@ module Async
51
77
  count.times do
52
78
  @queue.push(value)
53
79
  end
80
+
81
+ update_utilization_metrics
54
82
  end
55
83
 
56
84
  # Get current limiter statistics.
@@ -60,6 +88,10 @@ module Async
60
88
  {
61
89
  waiting: @queue.waiting_count,
62
90
  available: @queue.size,
91
+ acquired_count: @acquired_count_metric.value,
92
+ available_count: @queue.size,
93
+ waiting_count: @queue.waiting_count,
94
+ reacquire_waiting_count: @reacquire_waiting_count_metric.value,
63
95
  timing: @timing.statistics
64
96
  }
65
97
  end
@@ -69,16 +101,36 @@ module Async
69
101
 
70
102
  # Acquire a resource from the queue with optional deadline.
71
103
  def acquire_resource(deadline, reacquire: false, **options)
104
+ @reacquire_waiting_count_metric.increment if reacquire
105
+ update_utilization_metrics if reacquire
106
+
72
107
  @mutex.unlock
73
- return @queue.pop(timeout: deadline&.remaining, **options)
108
+ resource = @queue.pop(timeout: deadline&.remaining, **options)
109
+ return resource
74
110
  ensure
75
111
  @mutex.lock
112
+ @reacquire_waiting_count_metric.decrement if reacquire
113
+ @acquired_count_metric.increment if resource
114
+ update_utilization_metrics if reacquire || resource
76
115
  end
77
116
 
78
117
  # Release a previously acquired resource back to the queue.
79
118
  def release_resource(value)
119
+ @mutex.synchronize do
120
+ @acquired_count_metric.decrement if @acquired_count_metric.value > 0
121
+ update_utilization_metrics
122
+ end
123
+
80
124
  # Return a default resource to the queue:
81
125
  @queue.push(value)
126
+ update_utilization_metrics
127
+ end
128
+
129
+ private
130
+
131
+ def update_utilization_metrics
132
+ @available_count_metric.set(@queue.size)
133
+ @waiting_count_metric.set(@queue.waiting_count)
82
134
  end
83
135
  end
84
136
  end
@@ -4,6 +4,7 @@
4
4
  # Copyright, 2020, by Bruno Sutic.
5
5
  # Copyright, 2025, by Shopify Inc.
6
6
  # Copyright, 2025, by Samuel Williams.
7
+ # Copyright, 2026, by William T. Nelson.
7
8
 
8
9
  require_relative "sliding_window"
9
10
 
@@ -25,8 +26,6 @@ module Async
25
26
  # Get current timing strategy statistics.
26
27
  # @returns [Hash] Statistics hash with current state.
27
28
  def statistics
28
- current_time = Time.now
29
-
30
29
  {
31
30
  name: "FixedWindow",
32
31
  window_duration: @duration,
@@ -7,6 +7,6 @@
7
7
 
8
8
  module Async
9
9
  module Limiter
10
- VERSION = "2.0.0"
10
+ VERSION = "2.2.0"
11
11
  end
12
12
  end
data/license.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  Copyright, 2020-2021, by Bruno Sutic.
4
4
  Copyright, 2025, by Francisco Mejia.
5
- Copyright, 2025, by Shopify Inc.
6
- Copyright, 2025, by Samuel Williams.
7
- Copyright, 2025, by William T. Nelson.
5
+ Copyright, 2025-2026, by Shopify Inc.
6
+ Copyright, 2025-2026, by Samuel Williams.
7
+ Copyright, 2025-2026, by William T. Nelson.
8
8
 
9
9
  Permission is hereby granted, free of charge, to any person obtaining a copy
10
10
  of this software and associated documentation files (the "Software"), to deal
data/readme.md CHANGED
@@ -20,6 +20,35 @@ Please see the [project documentation](https://socketry.github.io/async-limiter/
20
20
 
21
21
  - [Token Usage](https://socketry.github.io/async-limiter/guides/token-usage/index) - This guide explains how to use tokens for advanced resource management with `async-limiter`. Tokens provide sophisticated resource handling with support for re-acquisition and automatic cleanup.
22
22
 
23
+ ## Releases
24
+
25
+ Please see the [project releases](https://socketry.github.io/async-limiter/releases/index) for all releases.
26
+
27
+ ### v2.2.0
28
+
29
+ - Add `async-utilization` metrics for limiter telemetry counters.
30
+
31
+ ### v2.1.0
32
+
33
+ - Add telemetry counters to `Async::Limiter::Limited` and `Async::Limiter::Queued`: `acquired_count`, `available_count`, `waiting_count`, and `reacquire_waiting_count` for observability into limiter state.
34
+ - Add `as_json` and `to_json` methods to `Async::Limiter::Generic` for JSON serialization of limiter statistics.
35
+ - Fix unused variable warning in `Async::Limiter::Timing::FixedWindow`.
36
+
37
+ ### v2.0.0
38
+
39
+ The 2.0.x release should be considered somewhat unstable.
40
+
41
+ - **Breaking**: Complete API redesign. The v1.x classes (`Async::Limiter::Concurrent`, `Async::Limiter::Unlimited`, etc.) have been replaced with a new inheritance-based architecture.
42
+ - **Breaking**: Removed `blocking?` method due to inherent race conditions. Use `acquire(timeout: 0)` for non-blocking checks.
43
+ - **Breaking**: Timing strategies now use consumption-only model (no explicit `release` methods).
44
+ - **Breaking**: Window classes moved from `limiter/window/` to `limiter/timing/` with renamed classes.
45
+ - [New Architecture (replaces v1.x classes)](https://socketry.github.io/async-limiter/releases/index#new-architecture-\(replaces-v1.x-classes\))
46
+ - [Advanced Timeout Features](https://socketry.github.io/async-limiter/releases/index#advanced-timeout-features)
47
+ - [Cost-Based Acquisition](https://socketry.github.io/async-limiter/releases/index#cost-based-acquisition)
48
+ - [Enhanced Timing Strategies](https://socketry.github.io/async-limiter/releases/index#enhanced-timing-strategies)
49
+ - [Token-Based Resource Management](https://socketry.github.io/async-limiter/releases/index#token-based-resource-management)
50
+ - [Thread Safety and Performance](https://socketry.github.io/async-limiter/releases/index#thread-safety-and-performance)
51
+
23
52
  ## See Also
24
53
 
25
54
  - [falcon](https://github.com/socketry/falcon) - A high-performance web server
@@ -36,6 +65,22 @@ We welcome contributions to this project.
36
65
  4. Push to the branch (`git push origin my-new-feature`).
37
66
  5. Create new Pull Request.
38
67
 
68
+ ### Running Tests
69
+
70
+ To run the test suite:
71
+
72
+ ``` shell
73
+ bundle exec sus
74
+ ```
75
+
76
+ ### Making Releases
77
+
78
+ To make a new release:
79
+
80
+ ``` shell
81
+ bundle exec bake gem:release:patch # or minor or major
82
+ ```
83
+
39
84
  ### Developer Certificate of Origin
40
85
 
41
86
  In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
data/releases.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Releases
2
2
 
3
+ ## v2.2.0
4
+
5
+ - Add `async-utilization` metrics for limiter telemetry counters.
6
+
7
+ ## v2.1.0
8
+
9
+ - Add telemetry counters to `Async::Limiter::Limited` and `Async::Limiter::Queued`: `acquired_count`, `available_count`, `waiting_count`, and `reacquire_waiting_count` for observability into limiter state.
10
+ - Add `as_json` and `to_json` methods to `Async::Limiter::Generic` for JSON serialization of limiter statistics.
11
+ - Fix unused variable warning in `Async::Limiter::Timing::FixedWindow`.
12
+
3
13
  ## v2.0.0
4
14
 
5
15
  The 2.0.x release should be considered somewhat unstable.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-limiter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruno Sutic
8
8
  - Shopify Inc.
9
9
  - Samuel Williams
10
+ - William T. Nelson
10
11
  - Francisco Mejia
11
- - William
12
12
  bindir: bin
13
13
  cert_chain:
14
14
  - |
@@ -56,6 +56,20 @@ dependencies:
56
56
  - - ">="
57
57
  - !ruby/object:Gem::Version
58
58
  version: '2.31'
59
+ - !ruby/object:Gem::Dependency
60
+ name: async-utilization
61
+ requirement: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - "~>"
64
+ - !ruby/object:Gem::Version
65
+ version: '0.4'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '0.4'
59
73
  executables: []
60
74
  extensions: []
61
75
  extra_rdoc_files: []
@@ -99,14 +113,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
113
  requirements:
100
114
  - - ">="
101
115
  - !ruby/object:Gem::Version
102
- version: '3.2'
116
+ version: '3.3'
103
117
  required_rubygems_version: !ruby/object:Gem::Requirement
104
118
  requirements:
105
119
  - - ">="
106
120
  - !ruby/object:Gem::Version
107
121
  version: '0'
108
122
  requirements: []
109
- rubygems_version: 3.6.9
123
+ rubygems_version: 4.0.6
110
124
  specification_version: 4
111
125
  summary: Execution rate limiting for Async
112
126
  test_files: []
metadata.gz.sig CHANGED
Binary file