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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a14e168451294700f7c71bed654256c51bcf6742f186f8201f9aebe7a1a6e3e5
4
- data.tar.gz: 5d1995a758edad1c5f054bf665f101fa85ba00bb34eb729415eaf4a7a5f13c1e
3
+ metadata.gz: 45d402fb542e1179c77ef384e333750f8435f48f6ecc3fc0e9ac1a1e790184b4
4
+ data.tar.gz: '048682c2d4f5303e264f77ce31f2a8c0e519c829e4508ed308b0f4f7738ca71f'
5
5
  SHA512:
6
- metadata.gz: bb3c8fb96ff6f5fdec4fe33eff582ba3db6be91caf2714e28f6ba3b4fb79dccc7dbece841a82de1c2becf507c65124cea12257bbebf7ef856cd4fdf261cef725
7
- data.tar.gz: 4b242a9abeccf2844cdeba9a0c939f5846255db810f7cd14bafaf05eafebbf5e70f6b021d83683ca92be3e8205b796721ee1f2017990288c8a181c71e5cddfa8
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 positive" if amount < 0
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, amount)
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
- return {new_bucket_level, bucket_capacity, fill_rate}
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
@@ -1,3 +1,3 @@
1
1
  module Praroter
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
@@ -1,2 +1,2 @@
1
1
  #!/bin/bash
2
- redis-cli --ldb --eval lib/praroter/filly_bucket.lua filly_bucket.api.user:42.bucket_level filly_bucket.api.user:42.last_updated , 5000 100 1000
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.1
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-11-30 00:00:00.000000000 Z
12
+ date: 2020-12-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis