pecorino 0.7.1 → 0.7.2
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/workflows/ci.yml +42 -19
- data/.gitignore +1 -0
- data/CHANGELOG.md +4 -0
- data/README.md +22 -2
- data/Rakefile +12 -1
- data/gemfiles/Gemfile_ruby27_rails7 +19 -0
- data/gemfiles/Gemfile_ruby30_rails8 +15 -0
- data/lib/pecorino/adapters/base_adapter.rb +1 -1
- data/lib/pecorino/version.rb +1 -1
- data/pecorino.gemspec +1 -14
- data/rbi/pecorino.rbi +905 -0
- data/test/adapters/adapter_test_methods.rb +259 -0
- data/test/adapters/memory_adapter_test.rb +12 -0
- data/test/adapters/postgres_adapter_test.rb +69 -0
- data/test/adapters/redis_adapter_test.rb +27 -0
- data/test/adapters/sqlite_adapter_test.rb +46 -0
- data/test/block_test.rb +23 -0
- data/test/cached_throttle_test.rb +100 -0
- data/test/leaky_bucket_test.rb +161 -0
- data/test/pecorino_test.rb +9 -0
- data/test/test_helper.rb +12 -0
- data/test/throttle_test.rb +119 -0
- metadata +19 -138
- data/Gemfile +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df8db59f2303035498ca51c54787f664fbc000148965e3782e188e26b90fea31
|
4
|
+
data.tar.gz: 7e67b40c92846045b0e38c8e706622d6114e307b49a8efaaec287db144734fdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6906f549004f30b57bbf9c0ca9d2a36ba1183acf0aec863563786d9118d8f0a1094d0dc2b6eddcdeb7929be7af1f017df0063a5073a798c74cd2337888a4a3e0
|
7
|
+
data.tar.gz: d16cc4946a3205488afe0ab00cabc6f8a482e59751468513bec02fa0685ec77676db58b5bcb9d92d7d2fb7631e0a39fe823cfe2ecade824a0e241e45a37510fd
|
data/.github/workflows/ci.yml
CHANGED
@@ -1,21 +1,46 @@
|
|
1
1
|
name: CI
|
2
2
|
|
3
3
|
on:
|
4
|
-
|
4
|
+
pull_request:
|
5
|
+
push:
|
6
|
+
branches: [ main ]
|
5
7
|
|
6
8
|
env:
|
9
|
+
PGHOST: localhost
|
10
|
+
PGUSER: postgres
|
11
|
+
PGPASSWORD: postgres
|
7
12
|
BUNDLE_PATH: vendor/bundle
|
8
13
|
|
9
14
|
jobs:
|
15
|
+
lint:
|
16
|
+
name: "Lint"
|
17
|
+
runs-on: ubuntu-latest
|
18
|
+
env:
|
19
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/Gemfile_ruby27_rails7 # Linting should always align with the minimum Ruby version
|
20
|
+
steps:
|
21
|
+
- name: Checkout code
|
22
|
+
uses: actions/checkout@v4
|
23
|
+
|
24
|
+
- name: Set up Ruby
|
25
|
+
uses: ruby/setup-ruby@v1
|
26
|
+
with:
|
27
|
+
ruby-version: 2.7.7
|
28
|
+
bundler-cache: true
|
29
|
+
|
30
|
+
- name: Lint code for consistent style
|
31
|
+
run: bundle exec standardrb
|
32
|
+
|
10
33
|
test:
|
11
|
-
name: Tests
|
12
|
-
runs-on: ubuntu-
|
13
|
-
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
|
34
|
+
name: "Tests"
|
35
|
+
runs-on: ubuntu-latest
|
14
36
|
strategy:
|
37
|
+
fail-fast: false # We want both to run to completion
|
15
38
|
matrix:
|
16
|
-
|
17
|
-
-
|
18
|
-
-
|
39
|
+
gemfile_and_ruby:
|
40
|
+
- ["/gemfiles/Gemfile_ruby27_rails7", "2.7.7"]
|
41
|
+
- ["/gemfiles/Gemfile_ruby30_rails8", "3.2.2"]
|
42
|
+
env:
|
43
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile_and_ruby[0] }}
|
19
44
|
services:
|
20
45
|
postgres:
|
21
46
|
image: postgres
|
@@ -30,19 +55,17 @@ jobs:
|
|
30
55
|
ports:
|
31
56
|
- 6379:6379
|
32
57
|
steps:
|
33
|
-
- name:
|
58
|
+
- name: Install packages
|
59
|
+
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y curl libjemalloc2 sqlite3
|
60
|
+
|
61
|
+
- name: Checkout code
|
34
62
|
uses: actions/checkout@v4
|
35
|
-
|
63
|
+
|
64
|
+
- name: Set up Ruby
|
36
65
|
uses: ruby/setup-ruby@v1
|
37
66
|
with:
|
38
|
-
ruby-version:
|
67
|
+
ruby-version: ${{ matrix.gemfile_and_ruby[1] }}
|
39
68
|
bundler-cache: true
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
PGHOST: localhost
|
44
|
-
PGUSER: postgres
|
45
|
-
PGPASSWORD: postgres
|
46
|
-
TESTOPTS: "--fail-fast"
|
47
|
-
# MYSQL_HOST: 127.0.0.1
|
48
|
-
# MYSQL_PORT: 3306
|
69
|
+
|
70
|
+
- name: Run tests
|
71
|
+
run: bundle exec rake test
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -182,6 +182,20 @@ We recommend running the following bit of code every couple of hours (via cron o
|
|
182
182
|
Pecorino.prune!
|
183
183
|
```
|
184
184
|
|
185
|
+
## Testing your application
|
186
|
+
|
187
|
+
The Pecorino buckets and blocks are stateful. If you are not running tests with a transaction rollback, the rate limiters that got hit in a test case may interfere with other test cases you are running. Normally you will not notice this (if you are using the same database as the rest of your models), but we recommend adding this section to your global test case setup:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
setup do
|
191
|
+
# Delete all transient records
|
192
|
+
ActiveRecord::Base.connection.execute("TRUNCATE TABLE pecorino_blocks")
|
193
|
+
ActiveRecord::Base.connection.execute("TRUNCATE TABLE pecorino_leaky_buckets")
|
194
|
+
end
|
195
|
+
```
|
196
|
+
|
197
|
+
If you are using Redis, you may want to ensure it gets truncated/reset for every test case - or that parallel test case runners [each use a separate Redis database.](https://redis.io/docs/latest/commands/select/)
|
198
|
+
|
185
199
|
## Using cached throttles
|
186
200
|
|
187
201
|
If a throttle is triggered, Pecorino sets a "block" record for that throttle key. Any request to that throttle will fail until the block is lifted. If you are getting hammered by requests which are getting throttled, it might be a good idea to install a caching layer which will respond with a "rate limit exceeded" error even before hitting your database - until the moment when the block would be lifted. You can use any [ActiveSupport::Cache::Store](https://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html) to store your blocks. If you have a fast Rails cache configured, create a wrapped throttle:
|
@@ -216,9 +230,15 @@ ActiveRecord::Base.connection.execute("ALTER TABLE pecorino_blocks SET UNLOGGED"
|
|
216
230
|
|
217
231
|
## Development
|
218
232
|
|
219
|
-
After checking out the repo,
|
233
|
+
After checking out the repo, set the Gemfile appropriate to your Ruby version and run Rake for tests, lint etc.
|
234
|
+
Note that it is important to use the appropriate Gemfile per Ruby version and Rails version you want to test with. Due to some dependency shenanigans it is currently not very easy to have a single Gemfile.
|
235
|
+
|
236
|
+
```bash
|
237
|
+
$ rbenv local 2.7.7 && export BUNDLE_GEMFILE=gemfiles/Gemfile_ruby27_rails7 && bundle install
|
238
|
+
$ bundle exec rake
|
239
|
+
```
|
220
240
|
|
221
|
-
|
241
|
+
Then proceed to develop as normal. CI will run both the oldest supported dependencies and newest supported dependencies.
|
222
242
|
|
223
243
|
## Contributing
|
224
244
|
|
data/Rakefile
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "rake/testtask"
|
5
5
|
require "standard/rake"
|
6
|
+
require "yard"
|
7
|
+
|
8
|
+
YARD::Rake::YardocTask.new(:doc)
|
6
9
|
|
7
10
|
Rake::TestTask.new(:test) do |t|
|
8
11
|
t.libs << "test"
|
@@ -15,4 +18,12 @@ task :format do
|
|
15
18
|
`bundle exec magic_frozen_string_literal .`
|
16
19
|
end
|
17
20
|
|
18
|
-
task
|
21
|
+
task :generate_typedefs do
|
22
|
+
`bundle exec sord rbi/pecorino.rbi`
|
23
|
+
end
|
24
|
+
|
25
|
+
task default: [:test, :standard, :generate_typedefs]
|
26
|
+
|
27
|
+
# When building the gem, generate typedefs beforehand,
|
28
|
+
# so that they get included
|
29
|
+
Rake::Task["build"].enhance(["generate_typedefs"])
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
ruby ">= 2.7", "< 3.0"
|
6
|
+
|
7
|
+
gemspec path: ".."
|
8
|
+
|
9
|
+
gem "pg"
|
10
|
+
gem "sqlite3", "< 1.7"
|
11
|
+
gem "activesupport", "< 8.0"
|
12
|
+
gem "rake", "~> 13.0"
|
13
|
+
gem "minitest", "~> 5.0"
|
14
|
+
gem "redis", "~> 5", "< 6"
|
15
|
+
gem "yard"
|
16
|
+
gem "standard"
|
17
|
+
gem "rubocop", "< 1.65" # "`EnsureNode#body` is deprecated and will be changed"...
|
18
|
+
gem "magic_frozen_string_literal"
|
19
|
+
gem "sord"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
ruby ">= 3.0"
|
6
|
+
gemspec path: ".."
|
7
|
+
|
8
|
+
gem "pg"
|
9
|
+
gem "sqlite3"
|
10
|
+
gem "activesupport", ">= 8"
|
11
|
+
gem "rake", "~> 13.0"
|
12
|
+
gem "minitest", "~> 5.0"
|
13
|
+
gem "redis", "~> 5", "< 6"
|
14
|
+
gem "yard" # Not used under this Ruby version but the Rakefile includes it
|
15
|
+
gem "standard" # Not used but the Rakefile includes it
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# An adapter allows Pecorino throttles, leaky buckets and other
|
4
|
-
# resources to
|
4
|
+
# resources to interface with a data storage backend - a database, usually.
|
5
5
|
class Pecorino::Adapters::BaseAdapter
|
6
6
|
# Returns the state of a leaky bucket. The state should be a tuple of two
|
7
7
|
# values: the current level (Float) and whether the bucket is now at capacity (Boolean)
|
data/lib/pecorino/version.rb
CHANGED
data/pecorino.gemspec
CHANGED
@@ -23,24 +23,11 @@ Gem::Specification.new do |spec|
|
|
23
23
|
# Specify which files should be added to the gem when it is released.
|
24
24
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
25
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
26
|
-
`git ls-files -z`.split("\x0")
|
26
|
+
`git ls-files -z`.split("\x0")
|
27
27
|
end
|
28
28
|
spec.bindir = "exe"
|
29
29
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
30
|
spec.require_paths = ["lib"]
|
31
31
|
|
32
|
-
# Uncomment to register a new dependency of your gem
|
33
32
|
spec.add_dependency "activerecord", ">= 7"
|
34
|
-
spec.add_development_dependency "pg"
|
35
|
-
spec.add_development_dependency "sqlite3"
|
36
|
-
spec.add_development_dependency "activesupport", ">= 7"
|
37
|
-
spec.add_development_dependency "rake", "~> 13.0"
|
38
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
39
|
-
spec.add_development_dependency "standard"
|
40
|
-
spec.add_development_dependency "magic_frozen_string_literal"
|
41
|
-
spec.add_development_dependency "minitest-fail-fast"
|
42
|
-
spec.add_development_dependency "redis", "~> 5", "< 6"
|
43
|
-
|
44
|
-
# For more information and examples about making a new gem, checkout our
|
45
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
46
33
|
end
|