redis-throttler 0.1.5 → 0.1.6
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/ChangeLog.md +8 -0
- data/gemspec.yml +1 -0
- data/lib/redis-throttler/base.rb +1 -1
- data/lib/redis-throttler/model.rb +7 -5
- data/lib/redis-throttler/version.rb +1 -1
- data/spec/model_spec.rb +48 -0
- data/spec/object_spec.rb +42 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/throttler_spec.rb +35 -35
- metadata +17 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aee41934ea93c01a4563339083e4c04267b0cd89
|
4
|
+
data.tar.gz: 134b60d1f35fdb047bf7cd195eb0ca7153d26ec9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 486543f3afa4f34f92263547babf2a20245e285e88bc8c013827c660ae43d2ab9be645c6342767b66e86d5d1dc4ef7cf12cd0cf795ce71dd18c422aed4eb2b4c
|
7
|
+
data.tar.gz: 14db1b9b171195d51bf0fc5af2954adee390a8f7dcb5eb7115c49802353cc072e8b3a19181b22f9823c39d8018918f62b75059da91479df0d4750a6fc02f9fd1
|
data/ChangeLog.md
CHANGED
data/gemspec.yml
CHANGED
data/lib/redis-throttler/base.rb
CHANGED
@@ -18,29 +18,31 @@ module RedisThrottler
|
|
18
18
|
threshold = opts[:for] || 900
|
19
19
|
interval = opts[:interval] || 5
|
20
20
|
|
21
|
-
|
21
|
+
bucket_span = [interval, 600].max
|
22
|
+
|
23
|
+
throttler = RedisThrottler::Base.new("#{klass}:#{key}", bucket_interval: interval, bucket_span: bucket_span)
|
22
24
|
@limits[key] = "#{subject.to_s} limit #{limit} per #{threshold} sec"
|
23
25
|
|
24
26
|
# includes('?') will return true
|
25
|
-
method = "#{key}
|
27
|
+
method = "#{key}_throttler"
|
26
28
|
|
27
29
|
%w(limits limits?).each do |string|
|
28
30
|
define_singleton_method(string) { string.include?('?') || @limits }
|
29
|
-
define_method(string) { string.include?('?') || @limits
|
31
|
+
define_method(string) { string.include?('?') || self.class.instance_variable_get('@limits')}
|
30
32
|
end
|
31
33
|
|
32
34
|
# i used Procs because they don't complain about arity
|
33
35
|
# these Procs will return a string to be evaluated in context
|
34
36
|
|
35
37
|
methods = {
|
36
|
-
:exceeded? => proc { |to_call| "#{method}.exceeded? \"#{to_call}\", threshold: #{limit}, interval: #{
|
38
|
+
:exceeded? => proc { |to_call, within| "#{method}.exceeded? \"#{to_call}\", threshold: #{limit}, interval: #{within}" },
|
37
39
|
:increment => proc { |to_call| "#{method}.add(\"#{to_call}\")" },
|
38
40
|
:count => proc { |to_call, within| "#{method}.count(\"#{to_call}\", #{within})" }
|
39
41
|
}
|
40
42
|
|
41
43
|
# define the class & instance methods
|
42
44
|
# pass the id to access counters
|
43
|
-
define_singleton_method(method) {
|
45
|
+
define_singleton_method(method) { throttler }
|
44
46
|
define_method(method) { self.class.send method }
|
45
47
|
|
46
48
|
methods.each do |magic, meth|
|
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TestClass do
|
4
|
+
|
5
|
+
it 'should be able to define throttle' do
|
6
|
+
expect(TestClass).to respond_to :throttle
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should have a throttler for defined throttle' do
|
10
|
+
expect(TestClass.logins_throttler.class).to eq(RedisThrottler::Base)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should display limits as hash' do
|
14
|
+
expect(TestClass.limits).to be_a(Hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should respond to limits? correctly' do
|
18
|
+
expect(TestClass.limits?).to eq(true)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should be able to increment throttler by subject' do
|
22
|
+
TestClass.logins_increment('testid')
|
23
|
+
TestClass.logins_increment('testid')
|
24
|
+
expect(TestClass.logins_count('testid')).to eq(2)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should responsd to exceeded? correctly' do
|
28
|
+
TestClass.logins_throttler.add('testid', 10)
|
29
|
+
expect(TestClass.logins_exceeded?('testid')).to eq(true)
|
30
|
+
|
31
|
+
TestClass.logins_throttler.add('testid2', 9)
|
32
|
+
expect(TestClass.logins_exceeded?('testid2')).to eq(false)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should not be rate-limited after interval' do
|
36
|
+
expect(TestClass.logins_exceeded?('test3')).to eq(false)
|
37
|
+
10.times { TestClass.logins_increment('test3') }
|
38
|
+
expect(TestClass.logins_exceeded?('test3')).to eq(true)
|
39
|
+
Timecop.travel(60) do
|
40
|
+
expect(TestClass.logins_exceeded?('test3')).to eq(false)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should return counter value for subject within defined limits' do
|
45
|
+
10.times { TestClass.logins_increment('test4') }
|
46
|
+
expect(TestClass.logins_count('test4')).to eq(TestClass.logins_throttler.count('test4', 60))
|
47
|
+
end
|
48
|
+
end
|
data/spec/object_spec.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Instace of TestClass' do
|
4
|
+
before do
|
5
|
+
@test = TestClass.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should have a throttler for defined throttle' do
|
9
|
+
expect(@test.logins_throttler.class).to eq(RedisThrottler::Base)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should display limits as hash' do
|
13
|
+
expect(@test.limits).to be_a(Hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should respond to limits? correctly' do
|
17
|
+
expect(@test.limits?).to eq(true)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should be able to increment throttler by subject' do
|
21
|
+
@test.logins_increment
|
22
|
+
@test.logins_increment
|
23
|
+
expect(@test.logins_count).to eq(2)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should responsd to exceeded? correctly' do
|
27
|
+
10.times do
|
28
|
+
@test.logins_increment
|
29
|
+
end
|
30
|
+
expect(@test.logins_exceeded?).to eq(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should not be rate-limited after interval' do
|
34
|
+
Timecop.travel(60) do
|
35
|
+
expect(@test.logins_exceeded?).to eq(false)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should return counter value for subject within defined limits' do
|
40
|
+
expect(@test.logins_count).to eq(TestClass.logins_count(@test.id))
|
41
|
+
end
|
42
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,17 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'redis-throttler'
|
3
3
|
require 'redis-throttler/base'
|
4
|
+
require 'timecop'
|
4
5
|
|
6
|
+
class TestClass
|
7
|
+
include RedisThrottler
|
8
|
+
throttle :logins, limit: 10, for: 60
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@id = 1234
|
12
|
+
end
|
13
|
+
|
14
|
+
def id
|
15
|
+
@id
|
16
|
+
end
|
17
|
+
end
|
data/spec/throttler_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe RedisThrottler do
|
3
|
+
describe RedisThrottler::Base do
|
4
4
|
|
5
5
|
before do
|
6
6
|
@rl = RedisThrottler::Base.new('test')
|
@@ -24,18 +24,18 @@ describe RedisThrottler do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'should be able to add to the count for a given subject' do
|
27
|
-
@rl.add(
|
28
|
-
@rl.add(
|
27
|
+
@rl.add('value1')
|
28
|
+
@rl.add('value1')
|
29
29
|
expect(@rl.count('value1', 1)).to eq(2)
|
30
|
-
expect(@rl.count(
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
expect(@rl.count('value2', 1)).to eq(0)
|
31
|
+
Timecop.travel(60) do
|
32
|
+
expect(@rl.count('value1', 1)).to eq(0)
|
33
|
+
end
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'should be able to add to the count by more than 1' do
|
37
|
-
@rl.add(
|
38
|
-
expect(@rl.count(
|
37
|
+
@rl.add('value1', 3)
|
38
|
+
expect(@rl.count('value1', 1)).to eq(3)
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'should be able to add to the count for a non-string subject' do
|
@@ -43,9 +43,9 @@ describe RedisThrottler do
|
|
43
43
|
@rl.add(123)
|
44
44
|
expect(@rl.count(123, 1)).to eq(2)
|
45
45
|
expect(@rl.count(124, 1)).to eq(0)
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
Timecop.travel(10) do
|
47
|
+
expect(@rl.count(123, 1)).to eq(0)
|
48
|
+
end
|
49
49
|
end
|
50
50
|
|
51
51
|
it 'should return counter value' do
|
@@ -69,29 +69,29 @@ describe RedisThrottler do
|
|
69
69
|
expect(@rl.within_bounds?("value1", {:threshold => 10, :interval => 30})).to be false
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
72
|
+
it "accept a threshold and a block that gets executed once it's below the threshold" do
|
73
|
+
expect(@rl.count("key", 30)).to eq(0)
|
74
|
+
31.times do
|
75
|
+
@rl.add("key")
|
76
|
+
end
|
77
|
+
expect(@rl.count("key", 30)).to eq(31)
|
78
|
+
|
79
|
+
@value = nil
|
80
|
+
expect do
|
81
|
+
Timeout.timeout(1) do
|
82
|
+
@rl.exec_within_threshold("key", {:threshold => 30, :interval => 30}) do
|
83
|
+
@value = 2
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end.to raise_error(Timeout::Error)
|
87
|
+
expect(@value).to be nil
|
88
|
+
Timecop.travel(40) do
|
89
|
+
@rl.exec_within_threshold("key", {:threshold => 30, :interval => 30}) do
|
90
|
+
@value = 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
expect(@value).to be 1
|
94
|
+
end
|
95
95
|
|
96
96
|
it 'counts correclty if bucket_span equals count-interval ' do
|
97
97
|
@rl = RedisThrottler::Base.new('key', {:bucket_span => 10, bucket_interval: 1})
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-throttler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Surdam
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: timecop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.8'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.8'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: yard
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -118,6 +132,8 @@ files:
|
|
118
132
|
- lib/redis-throttler/model.rb
|
119
133
|
- lib/redis-throttler/version.rb
|
120
134
|
- redis-throttler.gemspec
|
135
|
+
- spec/model_spec.rb
|
136
|
+
- spec/object_spec.rb
|
121
137
|
- spec/spec_helper.rb
|
122
138
|
- spec/throttler_spec.rb
|
123
139
|
homepage: https://github.com/esurdam/redis-throttler#readme
|