rapidity 0.0.5.88265 → 0.0.5.88564
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/rapidity/limiter.lua +37 -0
- data/lib/rapidity/limiter.rb +31 -27
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc0bdcbad063ffce0142d3eacdad37e4ee78186ee4bb2092c1677c871fb52fa2
|
4
|
+
data.tar.gz: 15017d1bae8b36afc44d484616bc2fe5f21c85e868606c9dc137ad0f4c04a5f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68967c5c216162141ddf9be4871c47f4db4966b07ad2e2faac5950ec1987244a445df52e41693b3fcb6a324d7d61b640c1293b139d671059047e84778a5df3b0
|
7
|
+
data.tar.gz: a97d793eb5b42c556ee971c1484f25b5910f8576ba280bd60ce845780f79cd63fdd015a5618568b04b4e9bda83000995e3dda096d920d7aca3c33e8ef5a7c129
|
data/Gemfile.lock
CHANGED
@@ -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
|
data/lib/rapidity/limiter.rb
CHANGED
@@ -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
|
-
|
35
|
-
|
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 #=>
|
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
|
-
|
47
|
-
|
48
|
-
conn.
|
49
|
-
|
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 =
|
62
|
+
taken = result.to_i
|
54
63
|
|
55
|
-
if taken
|
56
|
-
|
57
|
-
|
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
|
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
|
-
|
76
|
-
|
77
|
-
|
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.
|
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-
|
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:
|