prop 0.3.5 → 0.3.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.
- data/VERSION +1 -1
- data/lib/prop.rb +11 -3
- data/prop.gemspec +2 -2
- data/test/test_prop.rb +29 -0
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.6
|
data/lib/prop.rb
CHANGED
@@ -13,7 +13,7 @@ class Prop
|
|
13
13
|
def self.create(key, threshold, message)
|
14
14
|
default = "#{key} threshold #{threshold} exceeded"
|
15
15
|
error = new(message || default)
|
16
|
-
error.retry_after = threshold - Time.now.to_i % threshold
|
16
|
+
error.retry_after = threshold - Time.now.to_i % threshold if threshold > 0
|
17
17
|
error.root_message = default
|
18
18
|
|
19
19
|
raise error
|
@@ -46,6 +46,10 @@ class Prop
|
|
46
46
|
define_prop_class_method "reset_#{handle}" do |*args|
|
47
47
|
reset(sanitized_prop_options([ handle ] + args, defaults))
|
48
48
|
end
|
49
|
+
|
50
|
+
define_prop_class_method "count_#{handle}" do |*args|
|
51
|
+
count(sanitized_prop_options([ handle ] + args, defaults))
|
52
|
+
end
|
49
53
|
end
|
50
54
|
|
51
55
|
def throttle?(options)
|
@@ -56,6 +60,9 @@ class Prop
|
|
56
60
|
counter = count(options)
|
57
61
|
|
58
62
|
if counter >= options[:threshold]
|
63
|
+
if options[:progressive]
|
64
|
+
writer.call(sanitized_prop_key(options.merge(:window_modifier => 1)), counter)
|
65
|
+
end
|
59
66
|
raise Prop::RateLimitExceededError.create(options[:key], options[:threshold], options[:message])
|
60
67
|
else
|
61
68
|
writer.call(sanitized_prop_key(options), counter + 1)
|
@@ -76,7 +83,8 @@ class Prop
|
|
76
83
|
|
77
84
|
# Builds the expiring cache key
|
78
85
|
def sanitized_prop_key(options)
|
79
|
-
|
86
|
+
window = (Time.now.to_i / options[:interval]) + options[:window_modifier].to_i
|
87
|
+
cache_key = "#{normalize_cache_key(options[:key])}/#{ window }"
|
80
88
|
"prop/#{Digest::MD5.hexdigest(cache_key)}"
|
81
89
|
end
|
82
90
|
|
@@ -84,7 +92,7 @@ class Prop
|
|
84
92
|
def sanitized_prop_options(args, defaults)
|
85
93
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
86
94
|
return {
|
87
|
-
:key => normalize_cache_key(args), :message => defaults[:message],
|
95
|
+
:key => normalize_cache_key(args), :message => defaults[:message], :progressive => defaults[:progressive],
|
88
96
|
:threshold => defaults[:threshold].to_i, :interval => defaults[:interval].to_i
|
89
97
|
}.merge(options)
|
90
98
|
end
|
data/prop.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{prop}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Morten Primdahl"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-08-03}
|
13
13
|
s.description = %q{A gem for implementing rate limiting}
|
14
14
|
s.email = %q{morten@zendesk.com}
|
15
15
|
s.extra_rdoc_files = [
|
data/test/test_prop.rb
CHANGED
@@ -111,6 +111,35 @@ class TestProp < Test::Unit::TestCase
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
+
should "not reset counter when violations happen during the time window for a progressive cache" do
|
115
|
+
start = Time.parse("2006-05-04 03:02:01")
|
116
|
+
Time.stubs(:now).returns(start)
|
117
|
+
|
118
|
+
Prop.setup :not_progressive, :threshold => 5, :interval => 10
|
119
|
+
|
120
|
+
assert_raises(Prop::RateLimitExceededError) do
|
121
|
+
6.times { Prop.throttle_not_progressive! }
|
122
|
+
end
|
123
|
+
|
124
|
+
Time.stubs(:now).returns(start + 5)
|
125
|
+
assert_raises(Prop::RateLimitExceededError) { Prop.throttle_not_progressive! }
|
126
|
+
Time.stubs(:now).returns(start + 15)
|
127
|
+
assert Prop.throttle_not_progressive!
|
128
|
+
|
129
|
+
Time.stubs(:now).returns(start)
|
130
|
+
Prop.setup :progressive, :threshold => 5, :interval => 10, :progressive => true
|
131
|
+
|
132
|
+
assert_raises(Prop::RateLimitExceededError) do
|
133
|
+
6.times { Prop.throttle_progressive! }
|
134
|
+
end
|
135
|
+
|
136
|
+
Time.stubs(:now).returns(start + 5)
|
137
|
+
assert_raises(Prop::RateLimitExceededError) { Prop.throttle_progressive! }
|
138
|
+
|
139
|
+
Time.stubs(:now).returns(start + 11)
|
140
|
+
assert_raises(Prop::RateLimitExceededError) { Prop.throttle_progressive! }
|
141
|
+
end
|
142
|
+
|
114
143
|
should "not increment the counter beyon the threshold" do
|
115
144
|
10.times do |i|
|
116
145
|
Prop.throttle!(:key => 'hello', :threshold => 5, :interval => 10) rescue nil
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 6
|
10
|
+
version: 0.3.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Morten Primdahl
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-08-03 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|