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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfcca80bad8895a9b45ed8a3ed0afe06b52a0c6a851d8506b102a82b5375c2a3
4
- data.tar.gz: 7f57dd803797acfdf29a8d7cae31854528012af249887ae49e398b992a48f9d4
3
+ metadata.gz: 2f94aa734cb0bb50657f5484bbdd8bfcaabc7c2d6b7d9329361d41456ba49db6
4
+ data.tar.gz: 97e01c53e828092ce60be1412a288a70446ec9cc5ab783a6fa6e3ba147de1ee5
5
5
  SHA512:
6
- metadata.gz: dea8f3c693c1d9b5412cdc50cd333d1de6b92d90ec1358ae3c3f5d03fef685649bccd4f6fcc8757e04aa7aba5b13411b325b69b374be0bf30a86d10c16977613
7
- data.tar.gz: ee00695a622947cbdc14a300d73d06a850abd2357b3c1357e7904e7c93f2ea5513a4edbb98349a896b5b39cc57b08e889a221e78319e5344f778000dd7059f06
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", leak_rate: 5, capacity: 5)
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}", leak_rate: 100 / 60.0 / 60.0, capacity: 100, block_for: 60*60*3)
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:, leak_rate:, capacity:)
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
 
@@ -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: 30, **)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pecorino
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
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.2.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-09 00:00:00.000000000 Z
11
+ date: 2024-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord