praroter 1.0.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a107a6850338e77ecac23ff79c3ec477fbdf6615cb6b58a705e2f575752d2493
4
- data.tar.gz: 595c3f911778b4fd1a8a6dd64da6e8c7b0185db0c3ca6fc34bfc3b6b4926f719
3
+ metadata.gz: a14e168451294700f7c71bed654256c51bcf6742f186f8201f9aebe7a1a6e3e5
4
+ data.tar.gz: 5d1995a758edad1c5f054bf665f101fa85ba00bb34eb729415eaf4a7a5f13c1e
5
5
  SHA512:
6
- metadata.gz: 6bb75c4e204bb148c9f7928689c3bf7c0d5c8fb356820a34a6a0160fd7f97606914ae73b561fa9ec3bdb5d1862028ce778e01e5e8145e5f7d7bd1f9eb1d11f72
7
- data.tar.gz: 99192564d7291ede39f07d5d7ee8c0f8c780c37f3faa45726ab141f8987445d5fa8b6c1eeb346cddb29de5e13e6bd241151d5080e26d3135a8a78a1e2f83a463
6
+ metadata.gz: bb3c8fb96ff6f5fdec4fe33eff582ba3db6be91caf2714e28f6ba3b4fb79dccc7dbece841a82de1c2becf507c65124cea12257bbebf7ef856cd4fdf261cef725
7
+ data.tar.gz: 4b242a9abeccf2844cdeba9a0c939f5846255db810f7cd14bafaf05eafebbf5e70f6b021d83683ca92be3e8205b796721ee1f2017990288c8a181c71e5cddfa8
data/README.md CHANGED
@@ -72,6 +72,7 @@ To capture that exception, add this to the controller:
72
72
 
73
73
  ```ruby
74
74
  rescue_from Praroter::Throttled do |e|
75
+ response.set_header('X-Ratelimit-Cost', e.bucket_state.drained)
75
76
  response.set_header('X-Ratelimit-Level', e.bucket_state.level)
76
77
  response.set_header('X-Ratelimit-Capacity', e.bucket_state.capacity)
77
78
  response.set_header('X-Ratelimit-Retry-After', e.retry_in_seconds)
@@ -140,7 +141,8 @@ def index
140
141
  sleep(2.242)
141
142
  end
142
143
 
143
- rescue_from Praroter::FillyBucket::Throttled do |e|
144
+ rescue_from Praroter::Throttled do |e|
145
+ response.set_header('X-Ratelimit-Cost', e.bucket_state.drained)
144
146
  response.set_header('X-Ratelimit-Level', e.bucket_state.level)
145
147
  response.set_header('X-Ratelimit-Capacity', e.bucket_state.capacity)
146
148
  response.set_header('X-Ratelimit-Retry-After', e.retry_in_seconds)
@@ -159,6 +161,7 @@ def api_ratelimit
159
161
  bucket_state = ratelimit_bucket.drain_block do
160
162
  yield
161
163
  end
164
+ response.set_header('X-Ratelimit-Cost', bucket_state.drained)
162
165
  response.set_header('X-Ratelimit-Level', bucket_state.level)
163
166
  response.set_header('X-Ratelimit-Capacity', bucket_state.capacity)
164
167
  end
@@ -0,0 +1,57 @@
1
+ module Praroter
2
+ module FillyBucket
3
+
4
+ class Bucket
5
+ attr_reader :key, :fill_rate, :capacity
6
+
7
+ def initialize(key, fill_rate, capacity, creator)
8
+ @key = key
9
+ @fill_rate = fill_rate
10
+ @capacity = capacity
11
+ @creator = creator
12
+ end
13
+
14
+ def state
15
+ @creator.run_lua_bucket_script(self, 0)
16
+ end
17
+
18
+ def empty?
19
+ state.empty?
20
+ end
21
+
22
+ def full?
23
+ state.full?
24
+ end
25
+
26
+ def throttle!
27
+ bucket_state = state
28
+ if bucket_state.empty?
29
+ remaining_block_time = ((bucket_state.capacity - bucket_state.level).abs / bucket_state.fill_rate) + 3
30
+ raise Praroter::Throttled.new(bucket_state, remaining_block_time)
31
+ end
32
+ bucket_state
33
+ end
34
+
35
+ def drain(amount)
36
+ raise ArgumentError, "drain amount must be positive" if amount < 0
37
+ @creator.run_lua_bucket_script(self, amount)
38
+ end
39
+
40
+ def drain_block
41
+ work_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
42
+ yield
43
+ work_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
44
+ drain(((work_end - work_start) * 1000).to_i)
45
+ end
46
+
47
+ def level_key
48
+ "filly_bucket.#{key}.bucket_level"
49
+ end
50
+
51
+ def last_updated_key
52
+ "filly_bucket.#{key}.last_updated"
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,15 @@
1
+ module Praroter
2
+ module FillyBucket
3
+
4
+ class BucketState < Struct.new(:level, :capacity, :fill_rate, :drained)
5
+ def empty?
6
+ level <= 0
7
+ end
8
+
9
+ def full?
10
+ level >= capacity
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -1,69 +1,6 @@
1
1
  module Praroter
2
-
3
2
  module FillyBucket
4
3
 
5
- class BucketState < Struct.new(:level, :capacity, :fill_rate)
6
- def empty?
7
- level <= 0
8
- end
9
-
10
- def full?
11
- level >= capacity
12
- end
13
- end
14
-
15
- class Bucket
16
- attr_reader :key, :fill_rate, :capacity
17
-
18
- def initialize(key, fill_rate, capacity, creator)
19
- @key = key
20
- @fill_rate = fill_rate
21
- @capacity = capacity
22
- @creator = creator
23
- end
24
-
25
- def state
26
- @creator.run_lua_bucket_script(self, 0)
27
- end
28
-
29
- def empty?
30
- state.empty?
31
- end
32
-
33
- def full?
34
- state.full?
35
- end
36
-
37
- def throttle!
38
- bucket_state = state
39
- if bucket_state.empty?
40
- remaining_block_time = ((bucket_state.capacity - bucket_state.level).abs / bucket_state.fill_rate) + 3
41
- raise Praroter::Throttled.new(bucket_state, remaining_block_time)
42
- end
43
- bucket_state
44
- end
45
-
46
- def drain(amount)
47
- raise ArgumentError, "drain amount must be positive" if amount < 0
48
- @creator.run_lua_bucket_script(self, amount)
49
- end
50
-
51
- def drain_block
52
- work_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
53
- yield
54
- work_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
55
- drain(((work_end - work_start) * 1000).to_i)
56
- end
57
-
58
- def level_key
59
- "filly_bucket.#{key}.bucket_level"
60
- end
61
-
62
- def last_updated_key
63
- "filly_bucket.#{key}.last_updated"
64
- end
65
- end
66
-
67
4
  class Creator
68
5
  LUA_SCRIPT_CODE = File.read(File.join(__dir__, "filly_bucket.lua"))
69
6
  LUA_SCRIPT_HASH = Digest::SHA1.hexdigest(LUA_SCRIPT_CODE)
@@ -86,7 +23,7 @@ module Praroter
86
23
  keys: [bucket.level_key, bucket.last_updated_key],
87
24
  argv: [bucket.capacity, bucket.fill_rate, amount]
88
25
  )
89
- BucketState.new(new_bucket_level, bucket_capacity, fill_rate)
26
+ BucketState.new(new_bucket_level, bucket_capacity, fill_rate, amount)
90
27
  rescue Redis::CommandError => e
91
28
  if e.message.include? "NOSCRIPT"
92
29
  # The Redis server has never seen this script before. Needs to run only once in the entire lifetime
@@ -103,5 +40,4 @@ module Praroter
103
40
  end
104
41
 
105
42
  end
106
-
107
43
  end
@@ -1,3 +1,3 @@
1
1
  module Praroter
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: praroter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kasper Grubbe
@@ -176,8 +176,10 @@ files:
176
176
  - bin/setup
177
177
  - docker-compose.yml
178
178
  - lib/praroter.rb
179
- - lib/praroter/filly_bucket.lua
180
- - lib/praroter/filly_bucket.rb
179
+ - lib/praroter/filly_bucket/bucket.rb
180
+ - lib/praroter/filly_bucket/bucket_state.rb
181
+ - lib/praroter/filly_bucket/creator.rb
182
+ - lib/praroter/filly_bucket/filly_bucket.lua
181
183
  - lib/praroter/null_logger.rb
182
184
  - lib/praroter/null_pool.rb
183
185
  - lib/praroter/throttled.rb