async-limiter 1.5.4 → 2.0.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/context/generic-limiter.md +167 -0
- data/context/getting-started.md +226 -0
- data/context/index.yaml +41 -0
- data/context/limited-limiter.md +184 -0
- data/context/queued-limiter.md +109 -0
- data/context/timing-strategies.md +666 -0
- data/context/token-usage.md +85 -0
- data/lib/async/limiter/generic.rb +160 -0
- data/lib/async/limiter/limited.rb +103 -0
- data/lib/async/limiter/queued.rb +85 -0
- data/lib/async/limiter/timing/burst.rb +153 -0
- data/lib/async/limiter/timing/fixed_window.rb +42 -0
- data/lib/async/limiter/timing/leaky_bucket.rb +146 -0
- data/lib/async/limiter/timing/none.rb +56 -0
- data/lib/async/limiter/timing/ordered.rb +58 -0
- data/lib/async/limiter/timing/sliding_window.rb +152 -0
- data/lib/async/limiter/token.rb +102 -0
- data/lib/async/limiter/version.rb +10 -3
- data/lib/async/limiter.rb +21 -7
- data/lib/metrics/provider/async/limiter/generic.rb +74 -0
- data/lib/metrics/provider/async/limiter.rb +7 -0
- data/lib/traces/provider/async/limiter/generic.rb +41 -0
- data/lib/traces/provider/async/limiter.rb +7 -0
- data/license.md +25 -0
- data/readme.md +45 -0
- data/releases.md +50 -0
- data.tar.gz.sig +0 -0
- metadata +68 -83
- metadata.gz.sig +0 -0
- data/lib/async/limiter/concurrent.rb +0 -101
- data/lib/async/limiter/constants.rb +0 -6
- data/lib/async/limiter/unlimited.rb +0 -53
- data/lib/async/limiter/window/continuous.rb +0 -21
- data/lib/async/limiter/window/fixed.rb +0 -21
- data/lib/async/limiter/window/sliding.rb +0 -21
- data/lib/async/limiter/window.rb +0 -296
data/license.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# MIT License
|
2
|
+
|
3
|
+
Copyright, 2020-2021, by Bruno Sutic.
|
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.
|
8
|
+
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
11
|
+
in the Software without restriction, including without limitation the rights
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
14
|
+
furnished to do so, subject to the following conditions:
|
15
|
+
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
17
|
+
copies or substantial portions of the Software.
|
18
|
+
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
25
|
+
SOFTWARE.
|
data/readme.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Async Limiter
|
2
|
+
|
3
|
+
A Ruby gem providing flexible concurrency and rate limiting for async applications.
|
4
|
+
|
5
|
+
[](https://github.com/socketry/async-limiter/actions?workflow=Test)
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
Please see the [project documentation](https://socketry.github.io/async-limiter/) for more details.
|
10
|
+
|
11
|
+
- [Getting Started](https://socketry.github.io/async-limiter/guides/getting-started/index) - This guide explains how to get started the `async-limiter` gem for controlling concurrency and rate limiting in Ruby applications.
|
12
|
+
|
13
|
+
- [Generic Limiter](https://socketry.github.io/async-limiter/guides/generic-limiter/index) - This guide explains the <code class="language-ruby">Async::Limiter::Generic</code> class, which provides unlimited concurrency by default and serves as the base implementation for all other limiters. It's ideal when you need timing constraints without concurrency limits, or when building custom limiter implementations.
|
14
|
+
|
15
|
+
- [Limited Limiter](https://socketry.github.io/async-limiter/guides/limited-limiter/index) - This guide explains the <code class="language-ruby">Async::Limiter::Limited</code> class, which provides semaphore-style concurrency control, enforcing a maximum number of concurrent operations. It's perfect for controlling concurrency when you have limited capacity or want to prevent system overload.
|
16
|
+
|
17
|
+
- [Queued Limiter](https://socketry.github.io/async-limiter/guides/queued-limiter/index) - This guide explains the <code class="language-ruby">Async::Limiter::Queued</code> class, which provides priority-based task scheduling with optional resource management. Its key feature is priority-based acquisition where higher priority tasks get access first, with optional support for distributing specific resources from a pre-populated queue.
|
18
|
+
|
19
|
+
- [Timing Strategies](https://socketry.github.io/async-limiter/guides/timing-strategies/index) - This guide explains how to use timing strategies to provide rate limiting and timing constraints that can be combined with any limiter. They control *when* operations can execute, while limiters control *how many* can execute concurrently.
|
20
|
+
|
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
|
+
|
23
|
+
## See Also
|
24
|
+
|
25
|
+
- [falcon](https://github.com/socketry/falcon) - A high-performance web server
|
26
|
+
- [async-http](https://github.com/socketry/async-http) - Asynchronous HTTP client and server
|
27
|
+
- [async](https://github.com/socketry/async) - The core async framework
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
We welcome contributions to this project.
|
32
|
+
|
33
|
+
1. Fork it.
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`).
|
35
|
+
3. Commit your changes (`git commit -am 'Add some feature'`).
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`).
|
37
|
+
5. Create new Pull Request.
|
38
|
+
|
39
|
+
### Developer Certificate of Origin
|
40
|
+
|
41
|
+
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.
|
42
|
+
|
43
|
+
### Community Guidelines
|
44
|
+
|
45
|
+
This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
|
data/releases.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Releases
|
2
|
+
|
3
|
+
## v2.0.0
|
4
|
+
|
5
|
+
The 2.0.x release should be considered somewhat unstable.
|
6
|
+
|
7
|
+
- **Breaking**: Complete API redesign. The v1.x classes (`Async::Limiter::Concurrent`, `Async::Limiter::Unlimited`, etc.) have been replaced with a new inheritance-based architecture.
|
8
|
+
- **Breaking**: Removed `blocking?` method due to inherent race conditions. Use `acquire(timeout: 0)` for non-blocking checks.
|
9
|
+
- **Breaking**: Timing strategies now use consumption-only model (no explicit `release` methods).
|
10
|
+
- **Breaking**: Window classes moved from `limiter/window/` to `limiter/timing/` with renamed classes.
|
11
|
+
|
12
|
+
### New Architecture (replaces v1.x classes)
|
13
|
+
|
14
|
+
- **New**: `Async::Limiter::Generic` - Unlimited concurrency with timing coordination (replaces `Async::Limiter::Unlimited`).
|
15
|
+
- **New**: `Async::Limiter::Limited` - Counting semaphore with configurable limits (replaces `Async::Limiter::Concurrent`).
|
16
|
+
- **New**: `Async::Limiter::Queued` - Queue-based resource distribution with priority/timeout support (completely new functionality).
|
17
|
+
|
18
|
+
### Advanced Timeout Features
|
19
|
+
|
20
|
+
- **New**: Unified timeout API - `acquire(timeout: 0/nil/seconds)` provides non-blocking and timed acquisition.
|
21
|
+
- **New**: Precise deadline tracking using `Async::Deadline` (requires async v2.31.0+).
|
22
|
+
- **New**: Convoy effect prevention - quick timeout operations not blocked by slow operations.
|
23
|
+
- **New**: Accurate timeout propagation - remaining time correctly passed through timing and concurrency layers.
|
24
|
+
|
25
|
+
### Cost-Based Acquisition
|
26
|
+
|
27
|
+
- **New**: Cost-based acquisition - `acquire(cost: 1.5)` for proportional resource consumption.
|
28
|
+
- **New**: Starvation prevention - validates cost against timing strategy `maximum_cost` capacity.
|
29
|
+
- **New**: Flexible operation weighting - light operations consume fewer resources than heavy ones.
|
30
|
+
|
31
|
+
### Enhanced Timing Strategies
|
32
|
+
|
33
|
+
- Add `Async::Limiter::Timing::LeakyBucket` for token bucket rate limiting with automatic leaking.
|
34
|
+
- Add `Async::Limiter::Timing::FixedWindow` for discrete time boundary enforcement.
|
35
|
+
- Rename `Async::Limiter::Timing::Window` to `Async::Limiter::Timing::SlidingWindow` for clarity.
|
36
|
+
- **Breaking**: Remove `release` methods from timing strategies (consumption-only model).
|
37
|
+
- **Breaking**: Remove `try_acquire` methods from timing strategies (unified timeout API).
|
38
|
+
|
39
|
+
### Token-Based Resource Management
|
40
|
+
|
41
|
+
- **New**: `acquire_token` method returns `Token` objects for advanced resource management.
|
42
|
+
- **New**: Token re-acquisition with different options - `token.acquire(priority: 5)`.
|
43
|
+
- **New**: Automatic token cleanup with block usage.
|
44
|
+
|
45
|
+
### Thread Safety and Performance
|
46
|
+
|
47
|
+
- **New**: Race condition elimination by moving timing coordination inside mutex.
|
48
|
+
- **New**: Fast path optimizations using `deadline.expired?` checks.
|
49
|
+
- **New**: Atomic timing coordination prevents race conditions in concurrent access.
|
50
|
+
- **Improved**: Test performance using time simulation instead of actual sleep calls.
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,46 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-limiter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno Sutic
|
8
|
-
|
8
|
+
- Shopify Inc.
|
9
|
+
- Samuel Williams
|
10
|
+
- Francisco Mejia
|
11
|
+
- William
|
9
12
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
|
13
|
+
cert_chain:
|
14
|
+
- |
|
15
|
+
-----BEGIN CERTIFICATE-----
|
16
|
+
MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
|
17
|
+
ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
|
18
|
+
CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
|
19
|
+
MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
|
20
|
+
MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
|
21
|
+
bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
|
22
|
+
igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
|
23
|
+
9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
|
24
|
+
sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
|
25
|
+
e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
|
26
|
+
XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
|
27
|
+
RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
|
28
|
+
tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
|
29
|
+
zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
|
30
|
+
xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
|
31
|
+
BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
|
32
|
+
aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
|
33
|
+
aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
|
34
|
+
cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl
|
35
|
+
xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/
|
36
|
+
c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp
|
37
|
+
8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws
|
38
|
+
JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP
|
39
|
+
eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt
|
40
|
+
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
41
|
+
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
42
|
+
-----END CERTIFICATE-----
|
43
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
44
|
dependencies:
|
13
45
|
- !ruby/object:Gem::Dependency
|
14
46
|
name: async
|
@@ -16,96 +48,50 @@ dependencies:
|
|
16
48
|
requirements:
|
17
49
|
- - ">="
|
18
50
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '3.0'
|
51
|
+
version: '2.31'
|
23
52
|
type: :runtime
|
24
53
|
prerelease: false
|
25
54
|
version_requirements: !ruby/object:Gem::Requirement
|
26
55
|
requirements:
|
27
56
|
- - ">="
|
28
57
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '3.0'
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: async-rspec
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '1.15'
|
40
|
-
type: :development
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '1.15'
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: rspec
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '3.10'
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '3.10'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: rubocop-rspec
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '2.0'
|
68
|
-
type: :development
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '2.0'
|
75
|
-
- !ruby/object:Gem::Dependency
|
76
|
-
name: standard
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - "~>"
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: '0.9'
|
82
|
-
type: :development
|
83
|
-
prerelease: false
|
84
|
-
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - "~>"
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: '0.9'
|
89
|
-
description:
|
90
|
-
email: code@brunosutic.com
|
58
|
+
version: '2.31'
|
91
59
|
executables: []
|
92
60
|
extensions: []
|
93
61
|
extra_rdoc_files: []
|
94
62
|
files:
|
63
|
+
- context/generic-limiter.md
|
64
|
+
- context/getting-started.md
|
65
|
+
- context/index.yaml
|
66
|
+
- context/limited-limiter.md
|
67
|
+
- context/queued-limiter.md
|
68
|
+
- context/timing-strategies.md
|
69
|
+
- context/token-usage.md
|
95
70
|
- lib/async/limiter.rb
|
96
|
-
- lib/async/limiter/
|
97
|
-
- lib/async/limiter/
|
98
|
-
- lib/async/limiter/
|
71
|
+
- lib/async/limiter/generic.rb
|
72
|
+
- lib/async/limiter/limited.rb
|
73
|
+
- lib/async/limiter/queued.rb
|
74
|
+
- lib/async/limiter/timing/burst.rb
|
75
|
+
- lib/async/limiter/timing/fixed_window.rb
|
76
|
+
- lib/async/limiter/timing/leaky_bucket.rb
|
77
|
+
- lib/async/limiter/timing/none.rb
|
78
|
+
- lib/async/limiter/timing/ordered.rb
|
79
|
+
- lib/async/limiter/timing/sliding_window.rb
|
80
|
+
- lib/async/limiter/token.rb
|
99
81
|
- lib/async/limiter/version.rb
|
100
|
-
- lib/async/limiter
|
101
|
-
- lib/async/limiter/
|
102
|
-
- lib/async/limiter
|
103
|
-
- lib/async/limiter/
|
82
|
+
- lib/metrics/provider/async/limiter.rb
|
83
|
+
- lib/metrics/provider/async/limiter/generic.rb
|
84
|
+
- lib/traces/provider/async/limiter.rb
|
85
|
+
- lib/traces/provider/async/limiter/generic.rb
|
86
|
+
- license.md
|
87
|
+
- readme.md
|
88
|
+
- releases.md
|
104
89
|
homepage: https://github.com/bruno-/async-limiter
|
105
90
|
licenses:
|
106
91
|
- MIT
|
107
|
-
metadata:
|
108
|
-
|
92
|
+
metadata:
|
93
|
+
documentation_uri: https://socketry.github.io/async-limiter/
|
94
|
+
source_code_uri: https://github.com/socketry/async-limiter.git
|
109
95
|
rdoc_options: []
|
110
96
|
require_paths:
|
111
97
|
- lib
|
@@ -113,15 +99,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
99
|
requirements:
|
114
100
|
- - ">="
|
115
101
|
- !ruby/object:Gem::Version
|
116
|
-
version: 2
|
102
|
+
version: '3.2'
|
117
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
104
|
requirements:
|
119
105
|
- - ">="
|
120
106
|
- !ruby/object:Gem::Version
|
121
107
|
version: '0'
|
122
108
|
requirements: []
|
123
|
-
rubygems_version: 3.
|
124
|
-
signing_key:
|
109
|
+
rubygems_version: 3.6.9
|
125
110
|
specification_version: 4
|
126
|
-
summary: Async
|
111
|
+
summary: Execution rate limiting for Async
|
127
112
|
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|
@@ -1,101 +0,0 @@
|
|
1
|
-
require "async/task"
|
2
|
-
require_relative "constants"
|
3
|
-
|
4
|
-
module Async
|
5
|
-
module Limiter
|
6
|
-
class Concurrent
|
7
|
-
attr_reader :count
|
8
|
-
|
9
|
-
attr_reader :limit
|
10
|
-
|
11
|
-
def initialize(limit = 1, parent: nil, queue: [])
|
12
|
-
@count = 0
|
13
|
-
@limit = limit
|
14
|
-
@waiting = queue
|
15
|
-
@parent = parent
|
16
|
-
|
17
|
-
validate!
|
18
|
-
end
|
19
|
-
|
20
|
-
def blocking?
|
21
|
-
limit_blocking?
|
22
|
-
end
|
23
|
-
|
24
|
-
def async(*queue_args, parent: (@parent || Task.current), **options)
|
25
|
-
acquire(*queue_args)
|
26
|
-
parent.async(**options) do |task|
|
27
|
-
yield task
|
28
|
-
ensure
|
29
|
-
release
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def sync(*queue_args)
|
34
|
-
acquire(*queue_args) do
|
35
|
-
yield(@parent || Task.current)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def acquire(*queue_args)
|
40
|
-
wait(*queue_args)
|
41
|
-
@count += 1
|
42
|
-
|
43
|
-
return unless block_given?
|
44
|
-
|
45
|
-
begin
|
46
|
-
yield
|
47
|
-
ensure
|
48
|
-
release
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def release
|
53
|
-
@count -= 1
|
54
|
-
|
55
|
-
resume_waiting
|
56
|
-
end
|
57
|
-
|
58
|
-
def limit=(new_limit)
|
59
|
-
validate_limit!(new_limit)
|
60
|
-
|
61
|
-
@limit = new_limit
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def limit_blocking?
|
67
|
-
@count >= @limit
|
68
|
-
end
|
69
|
-
|
70
|
-
def wait(*queue_args)
|
71
|
-
fiber = Fiber.current
|
72
|
-
|
73
|
-
if blocking?
|
74
|
-
@waiting.push(fiber, *queue_args) # queue_args used for custom queues
|
75
|
-
Task.yield while blocking?
|
76
|
-
end
|
77
|
-
rescue Exception # rubocop:disable Lint/RescueException
|
78
|
-
@waiting.delete(fiber)
|
79
|
-
raise
|
80
|
-
end
|
81
|
-
|
82
|
-
def resume_waiting
|
83
|
-
while !blocking? && (fiber = @waiting.shift)
|
84
|
-
fiber.resume if fiber.alive?
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def validate!
|
89
|
-
if @limit.finite? && (@limit % 1).nonzero?
|
90
|
-
raise ArgumentError, "limit must be a whole number"
|
91
|
-
end
|
92
|
-
|
93
|
-
validate_limit!
|
94
|
-
end
|
95
|
-
|
96
|
-
def validate_limit!(value = @limit)
|
97
|
-
raise ArgumentError, "limit must be greater than 1" if value < 1
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require "async/task"
|
2
|
-
|
3
|
-
module Async
|
4
|
-
module Limiter
|
5
|
-
class Unlimited
|
6
|
-
attr_reader :count
|
7
|
-
|
8
|
-
def initialize(parent: nil)
|
9
|
-
@count = 0
|
10
|
-
@parent = parent
|
11
|
-
end
|
12
|
-
|
13
|
-
def limit
|
14
|
-
Float::INFINITY
|
15
|
-
end
|
16
|
-
|
17
|
-
def blocking?
|
18
|
-
false
|
19
|
-
end
|
20
|
-
|
21
|
-
def async(parent: (@parent || Task.current), **options)
|
22
|
-
acquire
|
23
|
-
parent.async(**options) do |task|
|
24
|
-
yield task
|
25
|
-
ensure
|
26
|
-
release
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def sync(*queue_args)
|
31
|
-
acquire(*queue_args) do
|
32
|
-
yield(@parent || Task.current)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def acquire
|
37
|
-
@count += 1
|
38
|
-
|
39
|
-
return unless block_given?
|
40
|
-
|
41
|
-
begin
|
42
|
-
yield
|
43
|
-
ensure
|
44
|
-
release
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def release
|
49
|
-
@count -= 1
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require_relative "../window"
|
2
|
-
|
3
|
-
module Async
|
4
|
-
module Limiter
|
5
|
-
class Window
|
6
|
-
class Continuous < Window
|
7
|
-
def initialize(limit = 1, window: 1, parent: nil, lock: true, queue: [])
|
8
|
-
super(
|
9
|
-
limit,
|
10
|
-
type: :sliding, # type doesn't matter, but sliding is less work
|
11
|
-
burstable: false,
|
12
|
-
window: window,
|
13
|
-
parent: parent,
|
14
|
-
lock: lock,
|
15
|
-
queue: queue
|
16
|
-
)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require_relative "../window"
|
2
|
-
|
3
|
-
module Async
|
4
|
-
module Limiter
|
5
|
-
class Window
|
6
|
-
class Fixed < Window
|
7
|
-
def initialize(limit = 1, window: 1, parent: nil, lock: true, queue: [])
|
8
|
-
super(
|
9
|
-
limit,
|
10
|
-
type: :fixed,
|
11
|
-
burstable: true,
|
12
|
-
window: window,
|
13
|
-
parent: parent,
|
14
|
-
lock: lock,
|
15
|
-
queue: queue
|
16
|
-
)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require_relative "../window"
|
2
|
-
|
3
|
-
module Async
|
4
|
-
module Limiter
|
5
|
-
class Window
|
6
|
-
class Sliding < Window
|
7
|
-
def initialize(limit = 1, window: 1, parent: nil, lock: true, queue: [])
|
8
|
-
super(
|
9
|
-
limit,
|
10
|
-
type: :sliding,
|
11
|
-
burstable: true,
|
12
|
-
window: window,
|
13
|
-
parent: parent,
|
14
|
-
lock: lock,
|
15
|
-
queue: queue
|
16
|
-
)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|