pecorino 0.2.0 → 0.3.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
- data/CHANGELOG.md +5 -0
- data/README.md +2 -2
- data/lib/pecorino/leaky_bucket.rb +22 -3
- data/lib/pecorino/throttle.rb +5 -4
- data/lib/pecorino/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f94aa734cb0bb50657f5484bbdd8bfcaabc7c2d6b7d9329361d41456ba49db6
|
4
|
+
data.tar.gz: 97e01c53e828092ce60be1412a288a70446ec9cc5ab783a6fa6e3ba147de1ee5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d83ebb84009492403ca8950d181f4689b42782ab3f65f7fe5091cab92fc4f739ecd64625449ab784309a122f09e62525c262c71f3c602d3d538f4ac511a78e3
|
7
|
+
data.tar.gz: 93d3a2845713c6dc71ff1f35e5433fcbca6837fdb336db00a7e403e5719f1e65eadac7dc819301c8886d40dc3f99c59b196d64004145de786d0875c42b98e635
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## [0.3.0] - 2024-01-18
|
2
|
+
|
3
|
+
- Allow `over_time` in addition to `leak_rate`, which is a more intuitive parameter to tweak
|
4
|
+
- Set default `block_for` to the time it takes the bucket to leak out completely instead of 30 seconds
|
5
|
+
|
1
6
|
## [0.2.0] - 2024-01-09
|
2
7
|
|
3
8
|
- [Add support for SQLite](https://github.com/cheddar-me/pecorino/pull/9)
|
data/README.md
CHANGED
@@ -25,7 +25,7 @@ And then execute:
|
|
25
25
|
Once the installation is done you can use Pecorino to start defining your throttles. Imagine you have a resource called `vault` and you want to limit the number of updates to it to 5 per second. To achieve that, instantiate a new `Throttle` in your controller or job code, and then trigger it using `Throttle#request!`. A call to `request!` registers 1 token getting added to the bucket. If the bucket is full, or the throttle is currently in "block" mode (has recently been triggered), a `Pecorino::Throttle::Throttled` exception will be raised.
|
26
26
|
|
27
27
|
```ruby
|
28
|
-
throttle = Pecorino::Throttle.new(key: "vault",
|
28
|
+
throttle = Pecorino::Throttle.new(key: "vault", over_time: 1.second, capacity: 5)
|
29
29
|
throttle.request!
|
30
30
|
```
|
31
31
|
In a Rails controller you can then rescue from this exception to render the appropriate response:
|
@@ -58,7 +58,7 @@ return render :capacity_exceeded unless throttle.able_to_accept?
|
|
58
58
|
If you are dealing with a metered resource (like throughput, money, amount of storage...) you can supply the number of tokens to either `request!` or `able_to_accept?` to indicate the desired top-up of the leaky bucket. For example, if you are maintaining user wallets and want to ensure no more than 100 dollars may be taken from the wallet within a certain amount of time, you can do it like so:
|
59
59
|
|
60
60
|
```ruby
|
61
|
-
throttle = Pecorino::Throttle.new(key: "wallet_t_#{current_user.id}",
|
61
|
+
throttle = Pecorino::Throttle.new(key: "wallet_t_#{current_user.id}", over_time_: 1.hour, capacity: 100, block_for: 60*60*3)
|
62
62
|
throttle.request!(20) # Attempt to withdraw 20 dollars
|
63
63
|
throttle.request!(20) # Attempt to withdraw 20 dollars more
|
64
64
|
throttle.request!(20) # Attempt to withdraw 20 dollars more
|
@@ -59,21 +59,40 @@ class Pecorino::LeakyBucket
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
# The key (name) of the leaky bucket
|
63
|
+
# @return [String]
|
64
|
+
attr_reader :key
|
65
|
+
|
66
|
+
# The leak rate (tokens per second) of the bucket
|
67
|
+
# @return [Float]
|
68
|
+
attr_reader :leak_rate
|
69
|
+
|
70
|
+
# The capacity of the bucket in tokens
|
71
|
+
# @return [Float]
|
72
|
+
attr_reader :capacity
|
73
|
+
|
62
74
|
# Creates a new LeakyBucket. The object controls 1 row in the database is
|
63
75
|
# specific to the bucket key.
|
64
76
|
#
|
65
77
|
# @param key[String] the key for the bucket. The key also gets used
|
66
78
|
# to derive locking keys, so that operations on a particular bucket
|
67
79
|
# are always serialized.
|
68
|
-
# @param leak_rate[Float] the leak rate of the bucket, in tokens per second
|
80
|
+
# @param leak_rate[Float] the leak rate of the bucket, in tokens per second.
|
81
|
+
# Either `leak_rate` or `over_time` can be used, but not both.
|
82
|
+
# @param over_time[#to_f] over how many seconds the bucket will leak out to 0 tokens.
|
83
|
+
# The value is assumed to be the number of seconds
|
84
|
+
# - or a duration which returns the number of seconds from `to_f`.
|
85
|
+
# Either `leak_rate` or `over_time` can be used, but not both.
|
69
86
|
# @param capacity[Numeric] how many tokens is the bucket capped at.
|
70
87
|
# Filling up the bucket using `fillup()` will add to that number, but
|
71
88
|
# the bucket contents will then be capped at this value. So with
|
72
89
|
# bucket_capacity set to 12 and a `fillup(14)` the bucket will reach the level
|
73
90
|
# of 12, and will then immediately start leaking again.
|
74
|
-
def initialize(key:,
|
91
|
+
def initialize(key:, capacity:, leak_rate: nil, over_time: nil)
|
92
|
+
raise ArgumentError, "Either leak_rate: or over_time: must be specified" if leak_rate.nil? && over_time.nil?
|
93
|
+
raise ArgumentError, "Either leak_rate: or over_time: may be specified, but not both" if leak_rate && over_time
|
94
|
+
@leak_rate = leak_rate || (over_time.to_f / capacity)
|
75
95
|
@key = key
|
76
|
-
@leak_rate = leak_rate.to_f
|
77
96
|
@capacity = capacity.to_f
|
78
97
|
end
|
79
98
|
|
data/lib/pecorino/throttle.rb
CHANGED
@@ -43,13 +43,14 @@ class Pecorino::Throttle
|
|
43
43
|
end
|
44
44
|
|
45
45
|
# @param key[String] the key for both the block record and the leaky bucket
|
46
|
-
# @param block_for[Numeric] the number of seconds to block any further requests for
|
46
|
+
# @param block_for[Numeric] the number of seconds to block any further requests for. Defaults to time it takes
|
47
|
+
# the bucket to leak out to the level of 0
|
47
48
|
# @param leaky_bucket_options Options for `Pecorino::LeakyBucket.new`
|
48
49
|
# @see PecorinoLeakyBucket.new
|
49
|
-
def initialize(key:, block_for:
|
50
|
-
@key = key.to_s
|
51
|
-
@block_for = block_for.to_f
|
50
|
+
def initialize(key:, block_for: nil, **)
|
52
51
|
@bucket = Pecorino::LeakyBucket.new(key:, **)
|
52
|
+
@key = key.to_s
|
53
|
+
@block_for = block_for ? block_for.to_f : (@bucket.capacity / @bucket.leak_rate)
|
53
54
|
end
|
54
55
|
|
55
56
|
# Tells whether the throttle will let this number of requests pass without raising
|
data/lib/pecorino/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pecorino
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|