rapidity 0.0.5.88265 → 0.0.5.88564

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: 6faa9172962dc6c7004e59dc8e827f16572b99c41b586c7221539d2bf253dda5
4
- data.tar.gz: fb698e043084b6ad4491c2c85b785f9678aba9996f333e3df6bae45d6f76a76a
3
+ metadata.gz: dc0bdcbad063ffce0142d3eacdad37e4ee78186ee4bb2092c1677c871fb52fa2
4
+ data.tar.gz: 15017d1bae8b36afc44d484616bc2fe5f21c85e868606c9dc137ad0f4c04a5f1
5
5
  SHA512:
6
- metadata.gz: d76e69e666ae0ab3a541f8ce725b2aae485ac9c7218163bd23bcaf4023f33db748da42f5dab7b978699f3f0ac3c0cfce9b49e2933127b81613d7df4533bc7496
7
- data.tar.gz: 7434ad4f51dc20142d28f5df0bd004f79e8674dec8ac317683d18921626469525f81956ce4c3b7a8260c11cdb3cd7f281bb3f7f7aac5123e532899a9446d1587
6
+ metadata.gz: 68967c5c216162141ddf9be4871c47f4db4966b07ad2e2faac5950ec1987244a445df52e41693b3fcb6a324d7d61b640c1293b139d671059047e84778a5df3b0
7
+ data.tar.gz: a97d793eb5b42c556ee971c1484f25b5910f8576ba280bd60ce845780f79cd63fdd015a5618568b04b4e9bda83000995e3dda096d920d7aca3c33e8ef5a7c129
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rapidity (0.0.5.88265)
4
+ rapidity (0.0.5.88564)
5
5
  activesupport
6
6
  connection_pool
7
7
  redis
@@ -0,0 +1,37 @@
1
+ -- args: key, treshold, interval, count
2
+ -- returns: obtained count.
3
+
4
+ -- make some nicer looking variable names:
5
+ local retval = nil
6
+
7
+ -- Redis documentation recommends passing the keys separately so that Redis
8
+ -- can - in the future - verify that they live on the same shard of a cluster, and
9
+ -- raise an error if they are not. As far as can be understood this functionality is not
10
+ -- yet present, but if we can make a little effort to make ourselves more future proof
11
+ -- we should.
12
+ local key = KEYS[1]
13
+ local treshold = tonumber(ARGV[1])
14
+ local interval = tonumber(ARGV[2])
15
+ local count = tonumber(ARGV[3])
16
+
17
+ local current = 0
18
+ local to_return = 0
19
+
20
+ redis.call("SET", key, treshold, "EX", interval, "NX")
21
+ current = redis.call("DECRBY", key, count)
22
+
23
+ -- If we became below zero we must return some value back
24
+ if current < 0 then
25
+ to_return = math.min(count, math.abs(current))
26
+
27
+ -- set 0 to current counter value
28
+ redis.call("SET", key, 0, 'KEEPTTL')
29
+
30
+ -- return obtained part of requested count
31
+ retval = count - to_return
32
+ else
33
+ -- return full of requested count
34
+ retval = count
35
+ end
36
+
37
+ return retval
@@ -6,6 +6,7 @@ module Rapidity
6
6
 
7
7
  attr_reader :pool, :name, :interval, :threshold, :namespace
8
8
 
9
+ LUA_SCRIPT_CODE = File.read(File.join(__dir__, 'limiter.lua'))
9
10
 
10
11
  # Convert message to given class
11
12
  # @params pool - inititalized Redis pool
@@ -30,12 +31,12 @@ module Rapidity
30
31
  # @return remaining counter value
31
32
  def remains
32
33
  results = @pool.with do |conn|
33
- conn.multi do
34
- conn.set(key('remains'), threshold, ex: interval, nx: true)
35
- conn.get(key('remains'))
34
+ conn.multi do |pipeline|
35
+ pipeline.set(key('remains'), threshold, ex: interval, nx: true)
36
+ pipeline.get(key('remains'))
36
37
  end
37
38
  end
38
- results[1].to_i #=> conn.get(key('remains'))
39
+ results[1].to_i #=> pipeline.get(key('remains'))
39
40
  end
40
41
 
41
42
  # Obtain values from counter
@@ -43,38 +44,41 @@ module Rapidity
43
44
  def obtain(count = 5)
44
45
  count = count.abs
45
46
 
46
- results = @pool.with do |conn|
47
- conn.multi do
48
- conn.set(key('remains'), threshold, ex: interval, nx: true)
49
- conn.decrby(key('remains'), count)
47
+ result = begin
48
+ @pool.with do |conn|
49
+ conn.evalsha(@script, keys: [key('remains')], argv: [threshold, interval, count])
50
+ end
51
+ rescue Redis::CommandError => e
52
+ if e.message.include?('NOSCRIPT')
53
+ # The Redis server has never seen this script before. Needs to run only once in the entire lifetime
54
+ # of the Redis server, until the script changes - in which case it will be loaded under a different SHA
55
+ ensure_script_loaded
56
+ retry
57
+ else
58
+ raise e
50
59
  end
51
60
  end
52
61
 
53
- taken = results[1].to_i #=> conn.decrby(key('remains'), count)
62
+ taken = result.to_i
54
63
 
55
- if taken < 0
56
- overflow = taken.abs
57
- to_return = [count, overflow].min
58
-
59
- results = @pool.with do |conn|
60
- conn.multi do
61
- conn.set(key('remains'), threshold - to_return, ex: interval, nx: true)
62
- conn.incrby(key('remains'), to_return)
63
- conn.ttl(key('remains'))
64
- end
64
+ if taken == 0
65
+ ttl = @pool.with do |conn|
66
+ conn.ttl(key('remains'))
65
67
  end
66
68
 
67
- ttl = results[2].to_i #=> conn.ttl(key('remains'))
68
-
69
- # reset if no ttl present
70
- if ttl == -1
69
+ # UNKNOWN BUG? reset if no ttl present. Many years ago once upon time we meet our key without TTL
70
+ if ttl == -1
71
71
  STDERR.puts "ERROR[#{Time.now}]: TTL for key #{key('remains').inspect} disappeared!"
72
- @pool.with {|c| c.expire(key('remains'), interval) }
72
+ @pool.with {|c| c.expire(key('remains'), interval) }
73
73
  end
74
+ end
75
+
76
+ taken
77
+ end
74
78
 
75
- count - to_return
76
- else
77
- count
79
+ def ensure_script_loaded
80
+ @script = @pool.with do |conn|
81
+ conn.script(:load, LUA_SCRIPT_CODE)
78
82
  end
79
83
  end
80
84
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rapidity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5.88265
4
+ version: 0.0.5.88564
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yurusov Vlad
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-06-25 00:00:00.000000000 Z
12
+ date: 2022-06-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -235,6 +235,7 @@ files:
235
235
  - README.md
236
236
  - lib/rapidity.rb
237
237
  - lib/rapidity/composer.rb
238
+ - lib/rapidity/limiter.lua
238
239
  - lib/rapidity/limiter.rb
239
240
  - lib/rapidity/version.rb
240
241
  homepage: