rate_limit_control 0.1.1 → 0.1.2
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/.gitignore +1 -0
- data/README.md +30 -5
- data/lib/rate_limit_control.rb +56 -61
- data/lib/rate_limit_control/version.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1691c8fdde2802b9942b61e37d63a3bc83c380d
|
4
|
+
data.tar.gz: 6c492b7c8aa28e5e2e8930b5e03e28646f157e8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca14669d3e96df8e483f1424cddd56c0fa6c309d0ec78a7246f6b1cedf73097152263d8bcd9f51edf44224e58ce1e2c457abca780ed7fdb55da1d6668f3c83dd
|
7
|
+
data.tar.gz: 853a151d1a18edce50535b1990b736bb300fab5358851a5bfa7722e01718195b60f73582abd7c1a7ae260099b56e6fe4aa24867253201c6a713cbfcaf4c2bee2
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# Rate limit control
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
Take control of the rate limit of your actions. This gem is primarily designed to work with Redis, but you can adapt other key-value databases to work with it. It was inspired by this [post](https://medium.com/@pebneter/fast-and-simple-rate-limiting-with-ruby-on-rails-and-redis-68e76ba38ca4).
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -22,7 +20,34 @@ Or install it yourself as:
|
|
22
20
|
|
23
21
|
## Usage
|
24
22
|
|
25
|
-
|
23
|
+
Define the configurations of your actions:
|
24
|
+
|
25
|
+
```
|
26
|
+
action_config = {
|
27
|
+
action: 'rate_limit_example',
|
28
|
+
id: 'foobar',
|
29
|
+
allowed_requests: 5,
|
30
|
+
storage: Redis.new,
|
31
|
+
timeout: 30,
|
32
|
+
}
|
33
|
+
```
|
34
|
+
|
35
|
+
You need to set your action as a block inside the rate limit control:
|
36
|
+
```
|
37
|
+
RateLimitControl.new(action_config) do
|
38
|
+
puts "This action will be suspended after the 5th execution"
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
After the 5th execution, the next action will be blocked until the timeout ends up. All actions with the same configuration will be blocked during this time.
|
43
|
+
|
44
|
+
## Action params
|
45
|
+
|
46
|
+
* **action**: Action name;
|
47
|
+
* **id**: Id of the action, the same action could be executed by different requesters;
|
48
|
+
* **allowed_requests**: Number of requests allow to be executed during the timeout period;
|
49
|
+
* **storage**: Key-value database instance;
|
50
|
+
* **timeout**: Time in seconds to unblock actions;
|
26
51
|
|
27
52
|
## Development
|
28
53
|
|
data/lib/rate_limit_control.rb
CHANGED
@@ -1,79 +1,74 @@
|
|
1
1
|
require "rate_limit_control/version"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@session_counter = "#{configs[:action]}_#{configs[:id]}"
|
16
|
-
@storage = configs[:storage]
|
17
|
-
@timeout = configs[:timeout]
|
18
|
-
end
|
3
|
+
class RateLimitControl
|
4
|
+
attr_reader :action, :allowed_requests, :session_counter, :storage, :timeout
|
5
|
+
|
6
|
+
def initialize(configs)
|
7
|
+
@action = "locked_#{configs[:action]}_#{configs[:id]}_#{Time.now.to_s}"
|
8
|
+
@allowed_requests = configs[:allowed_requests]
|
9
|
+
@session_counter = "#{configs[:action]}_#{configs[:id]}"
|
10
|
+
@storage = configs[:storage]
|
11
|
+
@timeout = configs[:timeout]
|
12
|
+
call
|
13
|
+
yield
|
14
|
+
end
|
19
15
|
|
20
|
-
|
21
|
-
if session_counter_created?
|
22
|
-
increment_session_counter
|
23
|
-
set_action_as_blocked if actions_exceed_the_total_of_allowed?
|
24
|
-
else
|
25
|
-
create_session_counter
|
26
|
-
end
|
16
|
+
private
|
27
17
|
|
28
|
-
|
29
|
-
|
30
|
-
|
18
|
+
def call
|
19
|
+
if session_counter_created?
|
20
|
+
increment_session_counter
|
21
|
+
set_action_as_blocked if actions_exceed_the_total_of_allowed?
|
22
|
+
else
|
23
|
+
create_session_counter
|
31
24
|
end
|
32
25
|
|
33
|
-
|
26
|
+
action_blocked_log
|
27
|
+
while action_blocked?; end
|
28
|
+
action_executed_log
|
29
|
+
end
|
34
30
|
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
def session_counter_created?
|
32
|
+
storage.get(session_counter) != nil
|
33
|
+
end
|
38
34
|
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
def increment_session_counter
|
36
|
+
storage.incr(session_counter)
|
37
|
+
end
|
42
38
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
def set_action_as_blocked
|
40
|
+
storage.set(action, true)
|
41
|
+
storage.expire(action, action_timeout)
|
42
|
+
end
|
47
43
|
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
def actions_exceed_the_total_of_allowed?
|
45
|
+
total_of_actions_executed >= allowed_requests
|
46
|
+
end
|
51
47
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
def create_session_counter
|
49
|
+
storage.set(session_counter, 0)
|
50
|
+
storage.expire(session_counter, timeout)
|
51
|
+
end
|
56
52
|
|
57
|
-
|
58
|
-
|
59
|
-
|
53
|
+
def action_blocked_log
|
54
|
+
puts "Action is blocked" if action_blocked?
|
55
|
+
end
|
60
56
|
|
61
|
-
|
62
|
-
|
63
|
-
|
57
|
+
def action_blocked?
|
58
|
+
storage.get(action) != nil
|
59
|
+
end
|
64
60
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
61
|
+
def action_executed_log
|
62
|
+
puts action
|
63
|
+
puts "Request executed at #{Time.now.to_s}"
|
64
|
+
end
|
69
65
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
66
|
+
def action_timeout
|
67
|
+
actions_ahead = (total_of_actions_executed / allowed_requests) || 1
|
68
|
+
actions_ahead * timeout
|
69
|
+
end
|
74
70
|
|
75
|
-
|
76
|
-
|
77
|
-
end
|
71
|
+
def total_of_actions_executed
|
72
|
+
storage.get(session_counter).to_i
|
78
73
|
end
|
79
74
|
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.1.
|
1
|
+
class RateLimitControl
|
2
|
+
VERSION = "0.1.2"
|
3
3
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rate_limit_control
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Boniatti
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|