pause 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +24 -0
- data/lib/pause.rb +4 -0
- data/lib/pause/action.rb +21 -9
- data/lib/pause/analyzer.rb +5 -24
- data/lib/pause/redis/adapter.rb +11 -4
- data/lib/pause/version.rb +1 -1
- data/spec/pause/action_spec.rb +16 -5
- data/spec/pause/analyzer_spec.rb +3 -13
- data/spec/pause/redis/adapter_spec.rb +56 -0
- data/spec/spec_helper.rb +4 -0
- metadata +25 -38
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cebe59883ec6e4803896b89e61d88c53f43902cc
|
4
|
+
data.tar.gz: 86067516015b359cbe2becb8d2e5b71748484f70
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3538a2c610971934961be482f4531e43a1b614c4d48786484592f4e9c170ef5e4694055d1e8efb80839c62d636c93f997907fd5c9ed1df181adcf8bb6711d361
|
7
|
+
data.tar.gz: bb3921bf9935e98176a073ac2dabcf43c1786c75ce5e532b04497dba4a8dff039d28ed9a1f88b12fd9a5da6052259e762e1cba1a66bd87bf7288f7d771021e42
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
Pause
|
2
2
|
======
|
3
3
|
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/pause.png)](http://badge.fury.io/rb/pause)
|
4
5
|
[![Build status](https://secure.travis-ci.org/wanelo/pause.png)](http://travis-ci.org/wanelo/pause)
|
5
6
|
|
6
7
|
Pause is a flexible Redis-backed rate-limiting client. Use it to track events, with
|
@@ -173,6 +174,29 @@ while true
|
|
173
174
|
end
|
174
175
|
```
|
175
176
|
|
177
|
+
## Unblocking
|
178
|
+
|
179
|
+
Actions can be unblocked manually after they have been blocked.
|
180
|
+
|
181
|
+
To unblock all blocked identifiers for a single action:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
MyAction.unblock_all
|
185
|
+
```
|
186
|
+
|
187
|
+
To unblock a single identifier for an action:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
action = MyAction.new('hello')
|
191
|
+
|
192
|
+
action.ok?
|
193
|
+
# => false
|
194
|
+
|
195
|
+
action.unblock
|
196
|
+
|
197
|
+
action.ok?
|
198
|
+
# => true
|
199
|
+
```
|
176
200
|
|
177
201
|
## Contributing
|
178
202
|
|
data/lib/pause.rb
CHANGED
data/lib/pause/action.rb
CHANGED
@@ -50,7 +50,7 @@ module Pause
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def checks
|
53
|
-
self.class.
|
53
|
+
self.class.checks
|
54
54
|
end
|
55
55
|
|
56
56
|
def self.checks=(period_checks)
|
@@ -58,7 +58,7 @@ module Pause
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def increment!(count = 1, timestamp = Time.now.to_i)
|
61
|
-
|
61
|
+
adapter.increment(key, timestamp, count)
|
62
62
|
end
|
63
63
|
|
64
64
|
def rate_limited?
|
@@ -77,19 +77,23 @@ module Pause
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def self.tracked_identifiers
|
80
|
-
|
80
|
+
adapter.all_keys(self.class_scope)
|
81
81
|
end
|
82
82
|
|
83
83
|
def self.rate_limited_identifiers
|
84
|
-
|
84
|
+
adapter.rate_limited_keys(self.class_scope)
|
85
85
|
end
|
86
86
|
|
87
87
|
def self.unblock_all
|
88
|
-
|
88
|
+
adapter.delete_rate_limited_keys(self.class_scope)
|
89
|
+
end
|
90
|
+
|
91
|
+
def unblock
|
92
|
+
adapter.delete_rate_limited_key(scope, identifier)
|
89
93
|
end
|
90
94
|
|
91
95
|
def key
|
92
|
-
"#{self.scope}:#{
|
96
|
+
"#{self.scope}:#{identifier}"
|
93
97
|
end
|
94
98
|
|
95
99
|
# Actions can be globally disabled or re-enabled in a persistent
|
@@ -104,15 +108,15 @@ module Pause
|
|
104
108
|
# MyAction.disabled? => false
|
105
109
|
#
|
106
110
|
def self.enable
|
107
|
-
|
111
|
+
adapter.enable(class_scope)
|
108
112
|
end
|
109
113
|
|
110
114
|
def self.disable
|
111
|
-
|
115
|
+
adapter.disable(class_scope)
|
112
116
|
end
|
113
117
|
|
114
118
|
def self.enabled?
|
115
|
-
|
119
|
+
adapter.enabled?(class_scope)
|
116
120
|
end
|
117
121
|
|
118
122
|
def self.disabled?
|
@@ -121,6 +125,14 @@ module Pause
|
|
121
125
|
|
122
126
|
private
|
123
127
|
|
128
|
+
def self.adapter
|
129
|
+
Pause.adapter
|
130
|
+
end
|
131
|
+
|
132
|
+
def adapter
|
133
|
+
self.class.adapter
|
134
|
+
end
|
135
|
+
|
124
136
|
def self.class_scope
|
125
137
|
class_variable_get:@@class_scope if class_variable_defined?(:@@class_scope)
|
126
138
|
end
|
data/lib/pause/analyzer.rb
CHANGED
@@ -4,31 +4,7 @@ module Pause
|
|
4
4
|
class Analyzer
|
5
5
|
include Pause::Helper::Timing
|
6
6
|
|
7
|
-
attr_accessor :adapter
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@adapter ||= Pause::Redis::Adapter.new(Pause.config)
|
11
|
-
end
|
12
|
-
|
13
|
-
def increment(action, timestamp = Time.now.to_i, count = 1)
|
14
|
-
adapter.increment(action.key, timestamp, count)
|
15
|
-
end
|
16
|
-
|
17
7
|
def check(action)
|
18
|
-
analyze(action)
|
19
|
-
end
|
20
|
-
|
21
|
-
def tracked_identifiers(scope)
|
22
|
-
adapter.all_keys(scope)
|
23
|
-
end
|
24
|
-
|
25
|
-
def rate_limited_identifiers(scope)
|
26
|
-
adapter.rate_limited_keys(scope)
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def analyze(action)
|
32
8
|
timestamp = period_marker(Pause.config.resolution, Time.now.to_i)
|
33
9
|
set = adapter.key_history(action.key)
|
34
10
|
action.checks.each do |period_check|
|
@@ -48,5 +24,10 @@ module Pause
|
|
48
24
|
nil
|
49
25
|
end
|
50
26
|
|
27
|
+
private
|
28
|
+
|
29
|
+
def adapter
|
30
|
+
Pause.adapter
|
31
|
+
end
|
51
32
|
end
|
52
33
|
end
|
data/lib/pause/redis/adapter.rb
CHANGED
@@ -50,10 +50,11 @@ module Pause
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def delete_rate_limited_keys(scope)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
delete_rate_limited_ids scope, rate_limited_keys(scope)
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete_rate_limited_key(scope, id)
|
57
|
+
delete_rate_limited_ids scope, [id]
|
57
58
|
end
|
58
59
|
|
59
60
|
def disable(scope)
|
@@ -74,6 +75,12 @@ module Pause
|
|
74
75
|
|
75
76
|
private
|
76
77
|
|
78
|
+
def delete_rate_limited_ids(scope, ids)
|
79
|
+
increment_keys = ids.map{ |key| white_key(scope, key) }
|
80
|
+
rate_limited_keys = ids.map{ |key| rate_limited_key(scope, key) }
|
81
|
+
redis.del(increment_keys + rate_limited_keys)
|
82
|
+
end
|
83
|
+
|
77
84
|
def redis
|
78
85
|
@redis_conn ||= ::Redis.new(host: Pause.config.redis_host,
|
79
86
|
port: Pause.config.redis_port,
|
data/lib/pause/version.rb
CHANGED
data/spec/pause/action_spec.rb
CHANGED
@@ -27,7 +27,7 @@ describe Pause::Action do
|
|
27
27
|
it "should increment" do
|
28
28
|
time = Time.now
|
29
29
|
Timecop.freeze time do
|
30
|
-
Pause.
|
30
|
+
Pause.adapter.should_receive(:increment).with(action.key, time.to_i, 1)
|
31
31
|
action.increment!
|
32
32
|
end
|
33
33
|
end
|
@@ -58,7 +58,6 @@ describe Pause::Action do
|
|
58
58
|
action.increment! 1, time
|
59
59
|
|
60
60
|
action.ok?.should be_false
|
61
|
-
|
62
61
|
end
|
63
62
|
|
64
63
|
it "should return false and silently fail if redis is not available" do
|
@@ -99,7 +98,7 @@ describe Pause::Action do
|
|
99
98
|
end
|
100
99
|
end
|
101
100
|
|
102
|
-
describe "
|
101
|
+
describe ".tracked_identifiers" do
|
103
102
|
it "should return all the identifiers tracked (but not blocked) so far" do
|
104
103
|
action.increment!
|
105
104
|
other_action.increment!
|
@@ -112,7 +111,7 @@ describe Pause::Action do
|
|
112
111
|
end
|
113
112
|
end
|
114
113
|
|
115
|
-
describe "
|
114
|
+
describe ".rate_limited_identifiers" do
|
116
115
|
it "should return all the identifiers blocked" do
|
117
116
|
action.increment!(100, Time.now.to_i)
|
118
117
|
other_action.increment!(100, Time.now.to_i)
|
@@ -125,7 +124,7 @@ describe Pause::Action do
|
|
125
124
|
end
|
126
125
|
end
|
127
126
|
|
128
|
-
describe "
|
127
|
+
describe ".unblock_all" do
|
129
128
|
it "should unblock all the identifiers for a scope" do
|
130
129
|
10.times { action.increment! }
|
131
130
|
other_action.increment!
|
@@ -142,6 +141,18 @@ describe Pause::Action do
|
|
142
141
|
MyNotification.tracked_identifiers.should == [other_action.identifier]
|
143
142
|
end
|
144
143
|
end
|
144
|
+
|
145
|
+
describe "#unblock" do
|
146
|
+
it 'unblocks the specified id' do
|
147
|
+
10.times { action.increment! }
|
148
|
+
|
149
|
+
expect(action.ok?).to be_false
|
150
|
+
|
151
|
+
action.unblock
|
152
|
+
|
153
|
+
expect(action.ok?).to be_true
|
154
|
+
end
|
155
|
+
end
|
145
156
|
end
|
146
157
|
|
147
158
|
describe Pause::Action, ".check" do
|
data/spec/pause/analyzer_spec.rb
CHANGED
@@ -21,26 +21,16 @@ describe Pause::Analyzer do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
let(:analyzer) { Pause.analyzer }
|
24
|
-
let(:adapter) { Pause.
|
24
|
+
let(:adapter) { Pause.adapter }
|
25
25
|
let(:action) { FollowPushNotification.new("1243123") }
|
26
26
|
|
27
|
-
describe "#increment" do
|
28
|
-
it "should increment an action" do
|
29
|
-
time = Time.now
|
30
|
-
adapter.should_receive(:increment).with(action.key, time.to_i, 1)
|
31
|
-
Timecop.freeze time do
|
32
|
-
analyzer.increment(action)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
27
|
describe "#analyze" do
|
38
28
|
it "checks and blocks if max_allowed is reached" do
|
39
29
|
time = Time.now
|
40
30
|
adapter.should_receive(:rate_limit!).once.with(action.key, 12)
|
41
31
|
Timecop.freeze time do
|
42
32
|
5.times do
|
43
|
-
|
33
|
+
action.increment!
|
44
34
|
analyzer.check(action)
|
45
35
|
end
|
46
36
|
end
|
@@ -55,7 +45,7 @@ describe Pause::Analyzer do
|
|
55
45
|
it "should return blocked action if action is blocked" do
|
56
46
|
Timecop.freeze Time.now do
|
57
47
|
5.times do
|
58
|
-
|
48
|
+
action.increment!
|
59
49
|
end
|
60
50
|
analyzer.check(action).should be_a(Pause::RateLimitedEvent)
|
61
51
|
end
|
@@ -12,6 +12,7 @@ describe Pause::Redis::Adapter do
|
|
12
12
|
Pause.stub(:config).and_return(configuration)
|
13
13
|
Pause.config.stub(:resolution).and_return(resolution)
|
14
14
|
Pause.config.stub(:history).and_return(history)
|
15
|
+
redis_conn.flushall
|
15
16
|
end
|
16
17
|
|
17
18
|
let(:adapter) { Pause::Redis::Adapter.new(Pause.config) }
|
@@ -75,4 +76,59 @@ describe Pause::Redis::Adapter do
|
|
75
76
|
adapter.send(:white_key, "abc").should == "i:abc"
|
76
77
|
end
|
77
78
|
end
|
79
|
+
|
80
|
+
describe '#enable' do
|
81
|
+
it 'deletes the disabled flag in redis' do
|
82
|
+
adapter.disable("boom")
|
83
|
+
expect(adapter.disabled?("boom")).to be_true
|
84
|
+
adapter.enable("boom")
|
85
|
+
expect(adapter.disabled?("boom")).to be_false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#disable' do
|
90
|
+
it 'sets the disabled flag in redis' do
|
91
|
+
expect(adapter.enabled?("boom")).to be_true
|
92
|
+
adapter.disable("boom")
|
93
|
+
expect(adapter.enabled?("boom")).to be_false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#rate_limit!' do
|
98
|
+
it 'rate limits a key for a specific ttl' do
|
99
|
+
expect(adapter.rate_limited?('1')).to be_false
|
100
|
+
adapter.rate_limit!('1', 10)
|
101
|
+
expect(adapter.rate_limited?('1')).to be_true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#delete_rate_limited_keys' do
|
106
|
+
it 'calls redis del with all keys' do
|
107
|
+
adapter.rate_limit!('boom:1', 10)
|
108
|
+
adapter.rate_limit!('boom:2', 10)
|
109
|
+
|
110
|
+
expect(adapter.rate_limited?('boom:1')).to be_true
|
111
|
+
expect(adapter.rate_limited?('boom:2')).to be_true
|
112
|
+
|
113
|
+
adapter.delete_rate_limited_keys('boom')
|
114
|
+
|
115
|
+
expect(adapter.rate_limited?('boom:1')).to be_false
|
116
|
+
expect(adapter.rate_limited?('boom:2')).to be_false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe '#delete_rate_limit_key' do
|
121
|
+
it 'calls redis del with all keys' do
|
122
|
+
adapter.rate_limit!('boom:1', 10)
|
123
|
+
adapter.rate_limit!('boom:2', 10)
|
124
|
+
|
125
|
+
expect(adapter.rate_limited?('boom:1')).to be_true
|
126
|
+
expect(adapter.rate_limited?('boom:2')).to be_true
|
127
|
+
|
128
|
+
adapter.delete_rate_limited_key('boom', '1')
|
129
|
+
|
130
|
+
expect(adapter.rate_limited?('boom:1')).to be_false
|
131
|
+
expect(adapter.rate_limited?('boom:2')).to be_true
|
132
|
+
end
|
133
|
+
end
|
78
134
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pause
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.6
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Atasay Gokkaya
|
@@ -12,102 +11,90 @@ authors:
|
|
12
11
|
autorequire:
|
13
12
|
bindir: bin
|
14
13
|
cert_chain: []
|
15
|
-
date:
|
14
|
+
date: 2014-05-23 00:00:00.000000000 Z
|
16
15
|
dependencies:
|
17
16
|
- !ruby/object:Gem::Dependency
|
18
17
|
name: redis
|
19
18
|
requirement: !ruby/object:Gem::Requirement
|
20
|
-
none: false
|
21
19
|
requirements:
|
22
|
-
- -
|
20
|
+
- - ">="
|
23
21
|
- !ruby/object:Gem::Version
|
24
22
|
version: '0'
|
25
23
|
type: :runtime
|
26
24
|
prerelease: false
|
27
25
|
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
26
|
requirements:
|
30
|
-
- -
|
27
|
+
- - ">="
|
31
28
|
- !ruby/object:Gem::Version
|
32
29
|
version: '0'
|
33
30
|
- !ruby/object:Gem::Dependency
|
34
31
|
name: rspec
|
35
32
|
requirement: !ruby/object:Gem::Requirement
|
36
|
-
none: false
|
37
33
|
requirements:
|
38
|
-
- -
|
34
|
+
- - ">="
|
39
35
|
- !ruby/object:Gem::Version
|
40
36
|
version: '0'
|
41
37
|
type: :development
|
42
38
|
prerelease: false
|
43
39
|
version_requirements: !ruby/object:Gem::Requirement
|
44
|
-
none: false
|
45
40
|
requirements:
|
46
|
-
- -
|
41
|
+
- - ">="
|
47
42
|
- !ruby/object:Gem::Version
|
48
43
|
version: '0'
|
49
44
|
- !ruby/object:Gem::Dependency
|
50
45
|
name: fakeredis
|
51
46
|
requirement: !ruby/object:Gem::Requirement
|
52
|
-
none: false
|
53
47
|
requirements:
|
54
|
-
- -
|
48
|
+
- - ">="
|
55
49
|
- !ruby/object:Gem::Version
|
56
50
|
version: '0'
|
57
51
|
type: :development
|
58
52
|
prerelease: false
|
59
53
|
version_requirements: !ruby/object:Gem::Requirement
|
60
|
-
none: false
|
61
54
|
requirements:
|
62
|
-
- -
|
55
|
+
- - ">="
|
63
56
|
- !ruby/object:Gem::Version
|
64
57
|
version: '0'
|
65
58
|
- !ruby/object:Gem::Dependency
|
66
59
|
name: timecop
|
67
60
|
requirement: !ruby/object:Gem::Requirement
|
68
|
-
none: false
|
69
61
|
requirements:
|
70
|
-
- -
|
62
|
+
- - ">="
|
71
63
|
- !ruby/object:Gem::Version
|
72
64
|
version: '0'
|
73
65
|
type: :development
|
74
66
|
prerelease: false
|
75
67
|
version_requirements: !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
68
|
requirements:
|
78
|
-
- -
|
69
|
+
- - ">="
|
79
70
|
- !ruby/object:Gem::Version
|
80
71
|
version: '0'
|
81
72
|
- !ruby/object:Gem::Dependency
|
82
73
|
name: guard-rspec
|
83
74
|
requirement: !ruby/object:Gem::Requirement
|
84
|
-
none: false
|
85
75
|
requirements:
|
86
|
-
- -
|
76
|
+
- - ">="
|
87
77
|
- !ruby/object:Gem::Version
|
88
78
|
version: '0'
|
89
79
|
type: :development
|
90
80
|
prerelease: false
|
91
81
|
version_requirements: !ruby/object:Gem::Requirement
|
92
|
-
none: false
|
93
82
|
requirements:
|
94
|
-
- -
|
83
|
+
- - ">="
|
95
84
|
- !ruby/object:Gem::Version
|
96
85
|
version: '0'
|
97
86
|
- !ruby/object:Gem::Dependency
|
98
87
|
name: rb-fsevent
|
99
88
|
requirement: !ruby/object:Gem::Requirement
|
100
|
-
none: false
|
101
89
|
requirements:
|
102
|
-
- -
|
90
|
+
- - ">="
|
103
91
|
- !ruby/object:Gem::Version
|
104
92
|
version: '0'
|
105
93
|
type: :development
|
106
94
|
prerelease: false
|
107
95
|
version_requirements: !ruby/object:Gem::Requirement
|
108
|
-
none: false
|
109
96
|
requirements:
|
110
|
-
- -
|
97
|
+
- - ">="
|
111
98
|
- !ruby/object:Gem::Version
|
112
99
|
version: '0'
|
113
100
|
description: Real time rate limiting for multi-process ruby environments based on
|
@@ -121,11 +108,11 @@ executables: []
|
|
121
108
|
extensions: []
|
122
109
|
extra_rdoc_files: []
|
123
110
|
files:
|
124
|
-
- .gitignore
|
125
|
-
- .pairs
|
126
|
-
- .rspec
|
127
|
-
- .rvmrc
|
128
|
-
- .travis.yml
|
111
|
+
- ".gitignore"
|
112
|
+
- ".pairs"
|
113
|
+
- ".rspec"
|
114
|
+
- ".rvmrc"
|
115
|
+
- ".travis.yml"
|
129
116
|
- Gemfile
|
130
117
|
- Guardfile
|
131
118
|
- LICENSE.txt
|
@@ -148,27 +135,26 @@ files:
|
|
148
135
|
- spec/support/fakeredis.rb
|
149
136
|
homepage: https://github.com/wanelo/pause
|
150
137
|
licenses: []
|
138
|
+
metadata: {}
|
151
139
|
post_install_message:
|
152
140
|
rdoc_options: []
|
153
141
|
require_paths:
|
154
142
|
- lib
|
155
143
|
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
-
none: false
|
157
144
|
requirements:
|
158
|
-
- -
|
145
|
+
- - ">="
|
159
146
|
- !ruby/object:Gem::Version
|
160
147
|
version: '0'
|
161
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
-
none: false
|
163
149
|
requirements:
|
164
|
-
- -
|
150
|
+
- - ">="
|
165
151
|
- !ruby/object:Gem::Version
|
166
152
|
version: '0'
|
167
153
|
requirements: []
|
168
154
|
rubyforge_project:
|
169
|
-
rubygems_version:
|
155
|
+
rubygems_version: 2.2.0
|
170
156
|
signing_key:
|
171
|
-
specification_version:
|
157
|
+
specification_version: 4
|
172
158
|
summary: RReal time rate limiting for multi-process ruby environments based on Redis
|
173
159
|
test_files:
|
174
160
|
- spec/pause/action_spec.rb
|
@@ -177,3 +163,4 @@ test_files:
|
|
177
163
|
- spec/pause/redis/adapter_spec.rb
|
178
164
|
- spec/spec_helper.rb
|
179
165
|
- spec/support/fakeredis.rb
|
166
|
+
has_rdoc:
|