praroter 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/praroter/filly_bucket/bucket.rb +7 -1
- data/lib/praroter/filly_bucket/creator.rb +2 -2
- data/lib/praroter/filly_bucket/filly_bucket.lua +18 -12
- data/lib/praroter/version.rb +1 -1
- data/scripts/test.sh +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: 45d402fb542e1179c77ef384e333750f8435f48f6ecc3fc0e9ac1a1e790184b4
|
4
|
+
data.tar.gz: '048682c2d4f5303e264f77ce31f2a8c0e519c829e4508ed308b0f4f7738ca71f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29965045ee43c7c5f3c1c4e77d7d3c7e8f60acfa61ae441d705a83f1e41fc3523d41385de551fda9060d185a86e53f1f769e5cab82748eec6ccb8a344ee3988c
|
7
|
+
data.tar.gz: 4526e457a81f08204de5ba456e5b2295ae4ee30f9c5dcf77222c8c8b3c536616212c2a71d36aba58be6ff29a331946364f5baba95d5660a68096ca11045b33cf
|
@@ -9,6 +9,10 @@ module Praroter
|
|
9
9
|
@fill_rate = fill_rate
|
10
10
|
@capacity = capacity
|
11
11
|
@creator = creator
|
12
|
+
|
13
|
+
raise ArgumentError, "key must be a string" if @key.class != String
|
14
|
+
raise ArgumentError, "fill_rate must be an integer" if @fill_rate.class != Integer
|
15
|
+
raise ArgumentError, "capacity must be an integer" if @capacity.class != Integer
|
12
16
|
end
|
13
17
|
|
14
18
|
def state
|
@@ -33,7 +37,9 @@ module Praroter
|
|
33
37
|
end
|
34
38
|
|
35
39
|
def drain(amount)
|
36
|
-
raise ArgumentError, "drain amount must be
|
40
|
+
raise ArgumentError, "drain amount must be an integer" if amount.class != Integer
|
41
|
+
raise ArgumentError, "drain amount must be a positive number" if amount < 0
|
42
|
+
|
37
43
|
@creator.run_lua_bucket_script(self, amount)
|
38
44
|
end
|
39
45
|
|
@@ -18,12 +18,12 @@ module Praroter
|
|
18
18
|
begin
|
19
19
|
# The script returns a tuple of "whole tokens, microtokens"
|
20
20
|
# to be able to smuggle the float across (similar to Redis TIME command)
|
21
|
-
new_bucket_level, bucket_capacity, fill_rate = r.evalsha(
|
21
|
+
new_bucket_level, bucket_capacity, fill_rate, scoop = r.evalsha(
|
22
22
|
LUA_SCRIPT_HASH,
|
23
23
|
keys: [bucket.level_key, bucket.last_updated_key],
|
24
24
|
argv: [bucket.capacity, bucket.fill_rate, amount]
|
25
25
|
)
|
26
|
-
BucketState.new(new_bucket_level, bucket_capacity, fill_rate,
|
26
|
+
BucketState.new(new_bucket_level, bucket_capacity, fill_rate, scoop)
|
27
27
|
rescue Redis::CommandError => e
|
28
28
|
if e.message.include? "NOSCRIPT"
|
29
29
|
# The Redis server has never seen this script before. Needs to run only once in the entire lifetime
|
@@ -33,19 +33,25 @@ local new_bucket_level = bucket_level + (fill_rate * dt) - scoop
|
|
33
33
|
-- and _then_ and add the tokens we fillup with
|
34
34
|
new_bucket_level = math.min(bucket_capacity, new_bucket_level)
|
35
35
|
|
36
|
-
-- Compute the key TTL for the bucket. We are interested in how long it takes the bucket
|
37
|
-
-- to leak all the way to bucket_capacity, as this is the time when the values stay relevant. We pad with 1 second
|
38
|
-
-- to have a little cushion.
|
39
|
-
local key_lifetime = nil
|
40
|
-
if new_bucket_level < 0 then -- if new_bucket_level is negative, then the TTL need to be longer
|
41
|
-
key_lifetime = math.ceil((math.abs(bucket_capacity - new_bucket_level) / fill_rate) + 1)
|
42
|
-
else
|
43
|
-
key_lifetime = math.ceil((bucket_capacity / fill_rate) + 1)
|
44
|
-
end
|
45
|
-
|
46
36
|
if new_bucket_level == bucket_capacity then
|
47
|
-
|
37
|
+
-- We subtract new_bucket_level with scoop to maintain expectations
|
38
|
+
-- there are cases where (bucket_level + (fill_rate * dt) - scoop) will be higher than
|
39
|
+
-- new_bucket_level, and in those cases consumers will expect to see:
|
40
|
+
-- {9995, 10000, 250, 5}
|
41
|
+
-- instead of:
|
42
|
+
-- {10000, 10000, 250, 5}
|
43
|
+
return {new_bucket_level - scoop, bucket_capacity, fill_rate, scoop}
|
48
44
|
else
|
45
|
+
-- Compute the key TTL for the bucket. We are interested in how long it takes the bucket
|
46
|
+
-- to leak all the way to bucket_capacity, as this is the time when the values stay relevant. We pad with 1 second
|
47
|
+
-- to have a little cushion.
|
48
|
+
local key_lifetime = nil
|
49
|
+
if new_bucket_level < 0 then -- if new_bucket_level is negative, then the TTL need to be longer
|
50
|
+
key_lifetime = math.ceil((math.abs(bucket_capacity - new_bucket_level) / fill_rate) + 1)
|
51
|
+
else
|
52
|
+
key_lifetime = math.ceil((bucket_capacity / fill_rate) + 1)
|
53
|
+
end
|
54
|
+
|
49
55
|
-- Save the new bucket level
|
50
56
|
redis.call("SETEX", bucket_level_key, key_lifetime, new_bucket_level)
|
51
57
|
|
@@ -53,5 +59,5 @@ else
|
|
53
59
|
-- can be correctly determined on the next invocation
|
54
60
|
redis.call("SETEX", last_updated_key, key_lifetime, now)
|
55
61
|
|
56
|
-
return {new_bucket_level, bucket_capacity, fill_rate}
|
62
|
+
return {new_bucket_level, bucket_capacity, fill_rate, scoop}
|
57
63
|
end
|
data/lib/praroter/version.rb
CHANGED
data/scripts/test.sh
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
#!/bin/bash
|
2
|
-
redis-cli --ldb --eval lib/praroter/filly_bucket.lua filly_bucket.api.
|
2
|
+
redis-cli --ldb --eval lib/praroter/filly_bucket/filly_bucket.lua filly_bucket.api.user_42.bucket_level filly_bucket.api.user_42.last_updated , 10000 250 1000
|
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.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kasper Grubbe
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-12-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|