ruby-limiter 2.3.0 → 2.3.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 +4 -4
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ci.yml +1 -2
- data/.github/workflows/cla.yml +23 -0
- data/.github/workflows/release.yml +30 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +0 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +71 -0
- data/README.md +13 -8
- data/dev.yml +1 -1
- data/lib/limiter/rate_queue.rb +14 -3
- data/lib/limiter/version.rb +1 -1
- data/limiter.gemspec +1 -1
- metadata +9 -9
- data/.github/workflows/gem-push.yml +0 -31
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3fa5f9a22fef901283796de71c5f8f9f2e3c15a0ec53437df63a8fd68ab6d68d
|
|
4
|
+
data.tar.gz: 0fb719626ac5314d31d195d0f5058bdb9830355a25648fcb45bed3317e6c2c39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: da3c41e851f8d076dbbae9cfdc6679c9c439091f83b84a15488c1a62d77e0f683a337acfb31b5dad4bc458cbe967d1929a1a50c3b7cd177ccdb1b12b80281335
|
|
7
|
+
data.tar.gz: 867e83f64c51472488d584b7eb751b2c8b9836ff8b771f29718d0a55023b95166dde55fe08de217f456030059e279551340c870eceb4ffef0cd5b5f033e7e2f8
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
registries:
|
|
3
|
+
github-com:
|
|
4
|
+
type: git
|
|
5
|
+
url: https://github.com
|
|
6
|
+
username: ${{secrets.DEPENDENCIES_GITHUB_USER}}
|
|
7
|
+
password: ${{secrets.DEPENDENCIES_GITHUB_TOKEN}}
|
|
8
|
+
updates:
|
|
9
|
+
- package-ecosystem: bundler
|
|
10
|
+
directory: "/"
|
|
11
|
+
schedule:
|
|
12
|
+
interval: daily
|
|
13
|
+
open-pull-requests-limit: 100
|
|
14
|
+
insecure-external-code-execution: allow
|
|
15
|
+
registries: "*"
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -30,7 +30,6 @@ jobs:
|
|
|
30
30
|
- name: Set up Ruby
|
|
31
31
|
uses: ruby/setup-ruby@v1
|
|
32
32
|
with:
|
|
33
|
-
ruby-version: 3.2
|
|
34
33
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
35
34
|
- name: Rubocop run
|
|
36
35
|
run: |
|
|
@@ -48,7 +47,7 @@ jobs:
|
|
|
48
47
|
runs-on: ubuntu-latest
|
|
49
48
|
strategy:
|
|
50
49
|
matrix:
|
|
51
|
-
ruby-version: ['3.
|
|
50
|
+
ruby-version: ['3.2', '3.3', '3.4']
|
|
52
51
|
|
|
53
52
|
steps:
|
|
54
53
|
- uses: actions/checkout@v3
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# .github/workflows/cla.yml
|
|
2
|
+
name: Contributor License Agreement (CLA)
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
pull_request_target:
|
|
6
|
+
types: [opened, synchronize]
|
|
7
|
+
issue_comment:
|
|
8
|
+
types: [created]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
cla:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
if: |
|
|
14
|
+
(github.event.issue.pull_request
|
|
15
|
+
&& !github.event.issue.pull_request.merged_at
|
|
16
|
+
&& contains(github.event.comment.body, 'signed')
|
|
17
|
+
)
|
|
18
|
+
|| (github.event.pull_request && !github.event.pull_request.merged)
|
|
19
|
+
steps:
|
|
20
|
+
- uses: Shopify/shopify-cla-action@v1
|
|
21
|
+
with:
|
|
22
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
23
|
+
cla-token: ${{ secrets.CLA_TOKEN }}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
release:
|
|
9
|
+
if: github.repository == 'Shopify/limiter'
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
id-token: write
|
|
15
|
+
|
|
16
|
+
environment: release
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout repository
|
|
20
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
21
|
+
with:
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
|
|
24
|
+
- name: Set up Ruby
|
|
25
|
+
uses: ruby/setup-ruby@e81a8fa391b11a595c1b7ed84177cc0fe02faf83 # v1.328.0
|
|
26
|
+
with:
|
|
27
|
+
bundler-cache: true
|
|
28
|
+
|
|
29
|
+
- name: Release gem on RubyGems.org
|
|
30
|
+
uses: rubygems/release-gem@7f9650160c1a4e7989fdc9855807bdbd421d8b6b # v1.4.1
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.4.4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## v2.3.1
|
|
4
|
+
|
|
5
|
+
- balanced mode now keeps calls `interval / size` apart after the queue has been idle; previously an idle interval let `size` calls through at once and the queue kept bursting until reset (#61)
|
|
6
|
+
- balanced ring is built from a single clock read (#62)
|
|
7
|
+
|
|
3
8
|
## v2.3.0
|
|
4
9
|
|
|
5
10
|
- add support for resetting RateQueue
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
ruby-limiter (2.3.1)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
ast (2.4.2)
|
|
10
|
+
code-scanning-rubocop (0.6.1)
|
|
11
|
+
rubocop (~> 1.0)
|
|
12
|
+
json (2.7.1)
|
|
13
|
+
language_server-protocol (3.17.0.3)
|
|
14
|
+
minitest (5.25.5)
|
|
15
|
+
minitest-focus (1.4.0)
|
|
16
|
+
minitest (>= 4, < 6)
|
|
17
|
+
mocha (2.1.0)
|
|
18
|
+
ruby2_keywords (>= 0.0.5)
|
|
19
|
+
parallel (1.24.0)
|
|
20
|
+
parser (3.3.0.5)
|
|
21
|
+
ast (~> 2.4.1)
|
|
22
|
+
racc
|
|
23
|
+
racc (1.7.3)
|
|
24
|
+
rainbow (3.1.1)
|
|
25
|
+
rake (13.3.0)
|
|
26
|
+
regexp_parser (2.9.0)
|
|
27
|
+
rexml (3.2.8)
|
|
28
|
+
strscan (>= 3.0.9)
|
|
29
|
+
rubocop (1.62.1)
|
|
30
|
+
json (~> 2.3)
|
|
31
|
+
language_server-protocol (>= 3.17.0)
|
|
32
|
+
parallel (~> 1.10)
|
|
33
|
+
parser (>= 3.3.0.2)
|
|
34
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
35
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
36
|
+
rexml (>= 3.2.5, < 4.0)
|
|
37
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
|
38
|
+
ruby-progressbar (~> 1.7)
|
|
39
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
40
|
+
rubocop-ast (1.31.2)
|
|
41
|
+
parser (>= 3.3.0.4)
|
|
42
|
+
rubocop-minitest (0.33.0)
|
|
43
|
+
rubocop (>= 1.39, < 2.0)
|
|
44
|
+
rubocop-rake (0.6.0)
|
|
45
|
+
rubocop (~> 1.0)
|
|
46
|
+
rubocop-shopify (2.15.1)
|
|
47
|
+
rubocop (~> 1.51)
|
|
48
|
+
ruby-progressbar (1.13.0)
|
|
49
|
+
ruby2_keywords (0.0.5)
|
|
50
|
+
strscan (3.1.0)
|
|
51
|
+
unicode-display_width (2.5.0)
|
|
52
|
+
|
|
53
|
+
PLATFORMS
|
|
54
|
+
arm64-darwin-23
|
|
55
|
+
ruby
|
|
56
|
+
|
|
57
|
+
DEPENDENCIES
|
|
58
|
+
bundler
|
|
59
|
+
code-scanning-rubocop (~> 0.6.1)
|
|
60
|
+
minitest (~> 5.20)
|
|
61
|
+
minitest-focus (~> 1.4)
|
|
62
|
+
mocha (~> 2.1)
|
|
63
|
+
rake (~> 13.0)
|
|
64
|
+
rubocop (~> 1.57)
|
|
65
|
+
rubocop-minitest (~> 0.33.0)
|
|
66
|
+
rubocop-rake (~> 0.6.0)
|
|
67
|
+
rubocop-shopify (~> 2.14)
|
|
68
|
+
ruby-limiter!
|
|
69
|
+
|
|
70
|
+
BUNDLED WITH
|
|
71
|
+
2.6.9
|
data/README.md
CHANGED
|
@@ -57,8 +57,8 @@ end
|
|
|
57
57
|
|
|
58
58
|
#### Load balancing
|
|
59
59
|
|
|
60
|
-
By default all calls to the `limit_method` will be bursted, e.g. as quick as possible, until the rate is exceeded.
|
|
61
|
-
|
|
60
|
+
By default all calls to the `limit_method` will be bursted, e.g. as quick as possible, until the rate is exceeded. Then
|
|
61
|
+
we wait for the remainder of the interval to continue. To even out the burst, an optional `balanced` parameter can be
|
|
62
62
|
provided to enable interleaving between the method calls, e.g: `interleave = interval / size`.
|
|
63
63
|
|
|
64
64
|
``` ruby
|
|
@@ -79,7 +79,8 @@ For example: with an interval of 60 seconds and a rate of 60:
|
|
|
79
79
|
|
|
80
80
|
There are times when it may be necessary to reset the rate limiter for a method, for example during testing.
|
|
81
81
|
|
|
82
|
-
This can be done by calling `reset_method_limit!` on the class, where "method" is replaced with the name of the method
|
|
82
|
+
This can be done by calling `reset_method_limit!` on the class, where "method" is replaced with the name of the method
|
|
83
|
+
being limited.
|
|
83
84
|
|
|
84
85
|
Given the example above, the following would reset the rate limit for the `tick` method during test setup:
|
|
85
86
|
|
|
@@ -96,8 +97,8 @@ end
|
|
|
96
97
|
### Advanced Usage
|
|
97
98
|
|
|
98
99
|
In cases where the mixin is not appropriate the `RateQueue` class can be used directly. As in the mixin examples above,
|
|
99
|
-
the `interval` parameter is optional (and defaults to 1 minute). It is also possible
|
|
100
|
-
|
|
100
|
+
the `interval` parameter is optional (and defaults to 1 minute). It is also possible to provide the block to
|
|
101
|
+
`RateQueue`, which will be executed on each limit hit (useful for metrics).
|
|
101
102
|
|
|
102
103
|
``` ruby
|
|
103
104
|
class Widget
|
|
@@ -118,7 +119,8 @@ end
|
|
|
118
119
|
|
|
119
120
|
#### Resetting a RateQueue
|
|
120
121
|
|
|
121
|
-
In some circumstances it may be desirable to reset a rate queue, for example after invoking an API that resets an
|
|
122
|
+
In some circumstances it may be desirable to reset a rate queue, for example after invoking an API that resets an
|
|
123
|
+
external rate limit.
|
|
122
124
|
|
|
123
125
|
This can be done by calling `reset` on the queue.
|
|
124
126
|
|
|
@@ -130,9 +132,12 @@ This can be done by calling `reset` on the queue.
|
|
|
130
132
|
|
|
131
133
|
## Development
|
|
132
134
|
|
|
133
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can
|
|
135
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can
|
|
136
|
+
also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
134
137
|
|
|
135
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
|
|
138
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
|
|
139
|
+
version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
|
|
140
|
+
push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
136
141
|
|
|
137
142
|
## Contributing
|
|
138
143
|
|
data/dev.yml
CHANGED
data/lib/limiter/rate_queue.rb
CHANGED
|
@@ -20,6 +20,7 @@ module Limiter
|
|
|
20
20
|
@mutex.synchronize do
|
|
21
21
|
@ring = @balanced ? balanced_ring : unbalanced_ring
|
|
22
22
|
@head = 0
|
|
23
|
+
@last = nil
|
|
23
24
|
end
|
|
24
25
|
end
|
|
25
26
|
|
|
@@ -29,9 +30,9 @@ module Limiter
|
|
|
29
30
|
@mutex.synchronize do
|
|
30
31
|
time = @ring[@head]
|
|
31
32
|
|
|
32
|
-
sleep_until(time
|
|
33
|
+
sleep_until(next_time(time))
|
|
33
34
|
|
|
34
|
-
@ring[@head] = clock.time
|
|
35
|
+
@last = @ring[@head] = clock.time
|
|
35
36
|
@head = (@head + 1) % @size
|
|
36
37
|
end
|
|
37
38
|
|
|
@@ -40,6 +41,13 @@ module Limiter
|
|
|
40
41
|
|
|
41
42
|
private
|
|
42
43
|
|
|
44
|
+
def next_time(time)
|
|
45
|
+
deadline = time + @interval
|
|
46
|
+
return deadline unless @balanced && @last
|
|
47
|
+
|
|
48
|
+
[deadline, @last + gap].max
|
|
49
|
+
end
|
|
50
|
+
|
|
43
51
|
def sleep_until(time)
|
|
44
52
|
interval = time - clock.time
|
|
45
53
|
return unless interval.positive?
|
|
@@ -57,7 +65,10 @@ module Limiter
|
|
|
57
65
|
end
|
|
58
66
|
|
|
59
67
|
def balanced_ring
|
|
60
|
-
|
|
68
|
+
start = base_time
|
|
69
|
+
step = gap
|
|
70
|
+
|
|
71
|
+
Array.new(@size) { |i| start + (step * i) }
|
|
61
72
|
end
|
|
62
73
|
|
|
63
74
|
def gap
|
data/lib/limiter/version.rb
CHANGED
data/limiter.gemspec
CHANGED
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.summary = "Simple Ruby rate limiting mechanism."
|
|
14
14
|
spec.homepage = "https://github.com/Shopify/limiter"
|
|
15
15
|
spec.license = "MIT"
|
|
16
|
-
spec.required_ruby_version = Gem::Requirement.new(">=
|
|
16
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
|
|
17
17
|
|
|
18
18
|
if spec.respond_to?(:metadata)
|
|
19
19
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-limiter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.3.
|
|
4
|
+
version: 2.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- S. Brent Faulkner
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: bundler
|
|
@@ -150,19 +149,22 @@ dependencies:
|
|
|
150
149
|
- - "~>"
|
|
151
150
|
- !ruby/object:Gem::Version
|
|
152
151
|
version: '2.14'
|
|
153
|
-
description:
|
|
154
152
|
email:
|
|
155
153
|
- brent.faulkner@shopify.com
|
|
156
154
|
executables: []
|
|
157
155
|
extensions: []
|
|
158
156
|
extra_rdoc_files: []
|
|
159
157
|
files:
|
|
158
|
+
- ".github/dependabot.yml"
|
|
160
159
|
- ".github/workflows/ci.yml"
|
|
161
|
-
- ".github/workflows/
|
|
160
|
+
- ".github/workflows/cla.yml"
|
|
161
|
+
- ".github/workflows/release.yml"
|
|
162
162
|
- ".gitignore"
|
|
163
163
|
- ".rubocop.yml"
|
|
164
|
+
- ".ruby-version"
|
|
164
165
|
- CHANGELOG.md
|
|
165
166
|
- Gemfile
|
|
167
|
+
- Gemfile.lock
|
|
166
168
|
- LICENSE.txt
|
|
167
169
|
- README.md
|
|
168
170
|
- Rakefile
|
|
@@ -183,7 +185,6 @@ licenses:
|
|
|
183
185
|
- MIT
|
|
184
186
|
metadata:
|
|
185
187
|
allowed_push_host: https://rubygems.org
|
|
186
|
-
post_install_message:
|
|
187
188
|
rdoc_options: []
|
|
188
189
|
require_paths:
|
|
189
190
|
- lib
|
|
@@ -191,15 +192,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
191
192
|
requirements:
|
|
192
193
|
- - ">="
|
|
193
194
|
- !ruby/object:Gem::Version
|
|
194
|
-
version:
|
|
195
|
+
version: 3.0.0
|
|
195
196
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
197
|
requirements:
|
|
197
198
|
- - ">="
|
|
198
199
|
- !ruby/object:Gem::Version
|
|
199
200
|
version: '0'
|
|
200
201
|
requirements: []
|
|
201
|
-
rubygems_version: 3.
|
|
202
|
-
signing_key:
|
|
202
|
+
rubygems_version: 3.6.7
|
|
203
203
|
specification_version: 4
|
|
204
204
|
summary: Simple Ruby rate limiting mechanism.
|
|
205
205
|
test_files: []
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
name: Ruby Gem
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags: [ "v*" ]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
build:
|
|
9
|
-
name: Build + Publish
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
permissions:
|
|
12
|
-
contents: read
|
|
13
|
-
packages: write
|
|
14
|
-
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v3
|
|
17
|
-
- name: Set up Ruby
|
|
18
|
-
uses: ruby/setup-ruby@v1
|
|
19
|
-
with:
|
|
20
|
-
ruby-version: 3.2
|
|
21
|
-
|
|
22
|
-
- name: Publish to RubyGems
|
|
23
|
-
run: |
|
|
24
|
-
mkdir -p $HOME/.gem
|
|
25
|
-
touch $HOME/.gem/credentials
|
|
26
|
-
chmod 0600 $HOME/.gem/credentials
|
|
27
|
-
printf -- "---\n:rubygems_api_key: ${RUBYGEMS_API_KEY}\n" > $HOME/.gem/credentials
|
|
28
|
-
gem build *.gemspec
|
|
29
|
-
gem push *.gem
|
|
30
|
-
env:
|
|
31
|
-
RUBYGEMS_API_KEY: "${{secrets.RUBYGEMS_API_KEY}}"
|