pecorino 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|