pause 0.0.5 → 0.0.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 +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
|
+
[](http://badge.fury.io/rb/pause)
|
4
5
|
[](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:
|