pause 0.0.3 → 0.0.4
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/.travis.yml +10 -0
- data/README.md +34 -15
- data/lib/pause.rb +2 -1
- data/lib/pause/action.rb +20 -12
- data/lib/pause/analyzer.rb +4 -4
- data/lib/pause/{blocked_action.rb → rate_limited_event.rb} +1 -1
- data/lib/pause/redis/adapter.rb +11 -11
- data/lib/pause/version.rb +1 -1
- data/pause.gemspec +1 -1
- data/spec/pause/action_spec.rb +38 -56
- data/spec/pause/analyzer_spec.rb +2 -2
- data/spec/pause/redis/adapter_spec.rb +3 -3
- data/spec/spec_helper.rb +1 -2
- metadata +4 -4
data/.travis.yml
ADDED
data/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
Pause
|
|
2
2
|
======
|
|
3
3
|
|
|
4
|
+
[](http://travis-ci.org/wanelo/pause)
|
|
5
|
+
|
|
4
6
|
Pause is a Redis-backed rate-limiting client. Use it to track events, with
|
|
5
7
|
rules around how often they are allowed to occur within configured time checks.
|
|
6
8
|
|
|
@@ -20,6 +22,8 @@ Or install it yourself as:
|
|
|
20
22
|
|
|
21
23
|
## Usage
|
|
22
24
|
|
|
25
|
+
### Configuration
|
|
26
|
+
|
|
23
27
|
Configure Pause. This could be in a Rails initializer.
|
|
24
28
|
|
|
25
29
|
* resolution - The time resolution (in seconds) defining the minimum period into which action counts are
|
|
@@ -38,26 +42,40 @@ Pause.configure do |config|
|
|
|
38
42
|
end
|
|
39
43
|
```
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
### Actions
|
|
46
|
+
|
|
47
|
+
Define local actions for your application. Actions define a scope by
|
|
48
|
+
which they are identified in the persistent store, and a set of checks. Checks define various
|
|
49
|
+
thresholds (`max_allowed`) against periods of time (`period_seconds`). When a threshold it triggered,
|
|
50
|
+
the action is rate limited, and stays rate limited for the duration of `block_ttl` seconds.
|
|
51
|
+
|
|
52
|
+
#### Checks
|
|
53
|
+
|
|
54
|
+
Checks are configured with the following arguments (which can be passed as an array, or a symbol hash):
|
|
55
|
+
|
|
56
|
+
* `period_seconds` - time window this is a time period against which an action is tested
|
|
57
|
+
* `max_allowed` - the maximum number of times an action can be incremented during this particular time period before rate limiting is triggered.
|
|
58
|
+
* `block_ttl` - amount time (seconds) an action stays rate limited after threshold is reached.
|
|
59
|
+
|
|
60
|
+
#### Scope
|
|
61
|
+
|
|
62
|
+
Scope is simple string used to identify this action in the Redis store, and is appended to all keys.
|
|
63
|
+
Therefore it is advised to keep scope as short as possible to reduce memory requirements of the store.
|
|
43
64
|
|
|
44
|
-
|
|
65
|
+
#### Resolution
|
|
45
66
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
period seconds
|
|
49
|
-
* `block_ttl` - how long to mark an action as blocked if it goes over max-allowed
|
|
67
|
+
Note that your resolution must be less than or equal to the smallest `period_seconds` value in your checks.
|
|
68
|
+
In other words, if your shortest check is 1 minute, you could set resolution to 1 minute or smaller.
|
|
50
69
|
|
|
51
|
-
|
|
52
|
-
Pause config. If you do so, you will actually be checking sums against the full time period.
|
|
70
|
+
#### Example
|
|
53
71
|
|
|
54
72
|
```ruby
|
|
55
73
|
require 'pause'
|
|
56
74
|
|
|
57
75
|
class FollowAction < Pause::Action
|
|
58
|
-
scope "
|
|
59
|
-
check
|
|
60
|
-
check
|
|
76
|
+
scope "f"
|
|
77
|
+
check period_seconds: 60, max_allowed: 100, block_ttl: 3600
|
|
78
|
+
check period_seconds: 1800, max_allowed: 2000, block_ttl: 3600
|
|
61
79
|
end
|
|
62
80
|
```
|
|
63
81
|
|
|
@@ -69,10 +87,11 @@ class FollowsController < ApplicationController
|
|
|
69
87
|
def create
|
|
70
88
|
action = FollowAction.new(user.id)
|
|
71
89
|
if action.ok?
|
|
72
|
-
# do stuff
|
|
90
|
+
# do stuff!
|
|
73
91
|
action.increment!
|
|
74
92
|
else
|
|
75
|
-
#
|
|
93
|
+
# action is rate limited, either skip
|
|
94
|
+
# or show error, depending on the context.
|
|
76
95
|
end
|
|
77
96
|
end
|
|
78
97
|
end
|
|
@@ -81,7 +100,7 @@ class OtherController < ApplicationController
|
|
|
81
100
|
def index
|
|
82
101
|
action = OtherAction.new(params[:thing])
|
|
83
102
|
if action.ok?
|
|
84
|
-
action.increment!(
|
|
103
|
+
action.increment!(params[:count].to_i, Time.now.to_i)
|
|
85
104
|
end
|
|
86
105
|
end
|
|
87
106
|
end
|
data/lib/pause.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
require 'redis'
|
|
1
2
|
require "pause/version"
|
|
2
3
|
require "pause/configuration"
|
|
3
4
|
require "pause/action"
|
|
4
5
|
require "pause/analyzer"
|
|
5
6
|
require "pause/redis/adapter"
|
|
6
|
-
require 'pause/
|
|
7
|
+
require 'pause/rate_limited_event'
|
|
7
8
|
|
|
8
9
|
module Pause
|
|
9
10
|
class PeriodCheck < Struct.new(:period_seconds, :max_allowed, :block_ttl)
|
data/lib/pause/action.rb
CHANGED
|
@@ -25,17 +25,23 @@ module Pause
|
|
|
25
25
|
# Action subclasses should define their checks as follows
|
|
26
26
|
#
|
|
27
27
|
# period_seconds - compare all activity by an identifier within the time period
|
|
28
|
-
# max_allowed
|
|
29
|
-
#
|
|
30
|
-
#
|
|
28
|
+
# max_allowed - if the number of actions by an identifier exceeds max_allowed for the time period marked
|
|
29
|
+
# by period_seconds, it is no longer ok.
|
|
30
|
+
# block_ttl - time to mark identifier as not ok
|
|
31
31
|
#
|
|
32
32
|
# class MyAction < Pause::Action
|
|
33
|
-
# check
|
|
34
|
-
# check
|
|
33
|
+
# check period_seconds: 60, max_allowed: 100, block_ttl: 3600
|
|
34
|
+
# check period_seconds: 1800, max_allowed: 2000, block_ttl: 3600
|
|
35
35
|
# end
|
|
36
36
|
#
|
|
37
|
-
def self.check(
|
|
37
|
+
def self.check(*args)
|
|
38
38
|
@checks ||= []
|
|
39
|
+
period_seconds, max_allowed, block_ttl =
|
|
40
|
+
if args.first.is_a?(Hash)
|
|
41
|
+
[args.first[:period_seconds], args.first[:max_allowed], args.first[:block_ttl]]
|
|
42
|
+
else
|
|
43
|
+
args
|
|
44
|
+
end
|
|
39
45
|
@checks << Pause::PeriodCheck.new(period_seconds, max_allowed, block_ttl)
|
|
40
46
|
end
|
|
41
47
|
|
|
@@ -51,17 +57,19 @@ module Pause
|
|
|
51
57
|
@checks = period_checks
|
|
52
58
|
end
|
|
53
59
|
|
|
54
|
-
def increment!(timestamp = Time.now.to_i
|
|
60
|
+
def increment!(count = 1, timestamp = Time.now.to_i)
|
|
55
61
|
Pause.analyzer.increment(self, timestamp, count)
|
|
56
62
|
end
|
|
57
63
|
|
|
64
|
+
def rate_limited?
|
|
65
|
+
! ok?
|
|
66
|
+
end
|
|
67
|
+
|
|
58
68
|
def ok?
|
|
59
|
-
return true if self.class.disabled?
|
|
60
69
|
Pause.analyzer.check(self).nil?
|
|
61
70
|
end
|
|
62
71
|
|
|
63
72
|
def analyze
|
|
64
|
-
return nil if self.class.disabled?
|
|
65
73
|
Pause.analyzer.check(self)
|
|
66
74
|
end
|
|
67
75
|
|
|
@@ -69,12 +77,12 @@ module Pause
|
|
|
69
77
|
Pause.analyzer.tracked_identifiers(self.class_scope)
|
|
70
78
|
end
|
|
71
79
|
|
|
72
|
-
def self.
|
|
73
|
-
Pause.analyzer.
|
|
80
|
+
def self.rate_limited_identifiers
|
|
81
|
+
Pause.analyzer.rate_limited_identifiers(self.class_scope)
|
|
74
82
|
end
|
|
75
83
|
|
|
76
84
|
def self.unblock_all
|
|
77
|
-
Pause.analyzer.adapter.
|
|
85
|
+
Pause.analyzer.adapter.delete_rate_limited_keys(self.class_scope)
|
|
78
86
|
end
|
|
79
87
|
|
|
80
88
|
def key
|
data/lib/pause/analyzer.rb
CHANGED
|
@@ -22,8 +22,8 @@ module Pause
|
|
|
22
22
|
adapter.all_keys(scope)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
def
|
|
26
|
-
adapter.
|
|
25
|
+
def rate_limited_identifiers(scope)
|
|
26
|
+
adapter.rate_limited_keys(scope)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
private
|
|
@@ -37,10 +37,10 @@ module Pause
|
|
|
37
37
|
break if element.ts < start_time
|
|
38
38
|
sum += element.count
|
|
39
39
|
if sum >= period_check.max_allowed
|
|
40
|
-
adapter.
|
|
40
|
+
adapter.rate_limit!(action.key, period_check.block_ttl)
|
|
41
41
|
# Note that Time.now is different from period_marker(resolution, Time.now), which
|
|
42
42
|
# rounds down to the nearest (resolution) seconds
|
|
43
|
-
return Pause::
|
|
43
|
+
return Pause::RateLimitedEvent.new(action, period_check, sum, Time.now.to_i)
|
|
44
44
|
end
|
|
45
45
|
sum
|
|
46
46
|
end
|
data/lib/pause/redis/adapter.rb
CHANGED
|
@@ -31,27 +31,27 @@ module Pause
|
|
|
31
31
|
extract_set_elements(white_key(key))
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def
|
|
35
|
-
redis.setex(
|
|
34
|
+
def rate_limit!(key, block_ttl)
|
|
35
|
+
redis.setex(rate_limited_key(key), block_ttl, nil)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def
|
|
39
|
-
!!redis.get(
|
|
38
|
+
def rate_limited?(key)
|
|
39
|
+
!!redis.get(rate_limited_key(key))
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def all_keys(scope)
|
|
43
43
|
keys(white_key(scope))
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def
|
|
47
|
-
keys(
|
|
46
|
+
def rate_limited_keys(scope)
|
|
47
|
+
keys(rate_limited_key(scope))
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def
|
|
51
|
-
ids =
|
|
50
|
+
def delete_rate_limited_keys(scope)
|
|
51
|
+
ids = rate_limited_keys(scope)
|
|
52
52
|
increment_keys = ids.map{ |key| white_key(scope, key) }
|
|
53
|
-
|
|
54
|
-
redis.del (increment_keys +
|
|
53
|
+
rate_limited_keys = ids.map{ |key| rate_limited_key(scope, key) }
|
|
54
|
+
redis.del (increment_keys + rate_limited_keys)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def disable(scope)
|
|
@@ -82,7 +82,7 @@ module Pause
|
|
|
82
82
|
["i", scope, key].compact.join(':')
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
def
|
|
85
|
+
def rate_limited_key(scope, key = nil)
|
|
86
86
|
["b", scope, key].compact.join(':')
|
|
87
87
|
end
|
|
88
88
|
|
data/lib/pause/version.rb
CHANGED
data/pause.gemspec
CHANGED
|
@@ -6,7 +6,7 @@ require 'pause/version'
|
|
|
6
6
|
Gem::Specification.new do |gem|
|
|
7
7
|
gem.name = "pause"
|
|
8
8
|
gem.version = Pause::VERSION
|
|
9
|
-
gem.authors = ["Atasay Gokkaya", "Paul Henry", "Eric
|
|
9
|
+
gem.authors = ["Atasay Gokkaya", "Paul Henry", "Eric Saxby"]
|
|
10
10
|
gem.email = %w(atasay@wanelo.com paul@wanelo.com sax@wanelo.com)
|
|
11
11
|
gem.description = %q(Real time redis rate limiting)
|
|
12
12
|
gem.summary = %q(Real time redis rate limiting)
|
data/spec/pause/action_spec.rb
CHANGED
|
@@ -6,8 +6,8 @@ describe Pause::Action do
|
|
|
6
6
|
|
|
7
7
|
class MyNotification < Pause::Action
|
|
8
8
|
scope "ipn:follow"
|
|
9
|
-
check 20, 5, 40
|
|
10
|
-
check 40, 7, 40
|
|
9
|
+
check period_seconds: 20, max_allowed: 5, block_ttl: 40
|
|
10
|
+
check period_seconds: 40, max_allowed: 7, block_ttl: 40
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
let(:resolution) { 10 }
|
|
@@ -47,73 +47,45 @@ describe Pause::Action do
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
it "should successfully consider different period checks" do
|
|
50
|
-
time = period_marker(resolution, Time.now.to_i
|
|
50
|
+
time = period_marker(resolution, Time.now.to_i)
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
action.increment!
|
|
55
|
-
action.ok?.should be_true
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
Timecop.freeze Time.at(time - 5) do
|
|
60
|
-
2.times do
|
|
61
|
-
action.increment!
|
|
62
|
-
action.ok?.should be_true
|
|
63
|
-
end
|
|
64
|
-
action.increment!
|
|
65
|
-
action.ok?.should be_false
|
|
66
|
-
end
|
|
67
|
-
end
|
|
52
|
+
action.increment! 4, time - 25
|
|
53
|
+
action.ok?.should be_true
|
|
68
54
|
|
|
69
|
-
|
|
55
|
+
action.increment! 2, time - 3
|
|
56
|
+
action.ok?.should be_true
|
|
70
57
|
|
|
71
|
-
|
|
72
|
-
10.times { action.increment! }
|
|
73
|
-
action.ok?.should be_false
|
|
58
|
+
action.increment! 1, time
|
|
74
59
|
|
|
75
|
-
|
|
60
|
+
action.ok?.should be_false
|
|
76
61
|
|
|
77
|
-
action.ok?.should be_true
|
|
78
|
-
end
|
|
79
62
|
end
|
|
80
63
|
end
|
|
81
64
|
|
|
82
65
|
describe "#analyze" do
|
|
83
|
-
context "action should not be
|
|
66
|
+
context "action should not be rate limited" do
|
|
84
67
|
it "returns nil" do
|
|
85
68
|
action.analyze.should be_nil
|
|
86
69
|
end
|
|
87
70
|
end
|
|
88
71
|
|
|
89
|
-
context "action should be
|
|
90
|
-
it "returns a
|
|
72
|
+
context "action should be rate limited" do
|
|
73
|
+
it "returns a RateLimitedEvent object" do
|
|
91
74
|
time = Time.now
|
|
92
|
-
|
|
75
|
+
rate_limit = nil
|
|
93
76
|
|
|
94
77
|
Timecop.freeze time do
|
|
95
78
|
7.times { action.increment! }
|
|
96
|
-
|
|
79
|
+
rate_limit = action.analyze
|
|
97
80
|
end
|
|
98
81
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
blocked_action.should be_a(Pause::BlockedAction)
|
|
102
|
-
blocked_action.identifier.should == expected_blocked_action.identifier
|
|
103
|
-
blocked_action.sum.should == expected_blocked_action.sum
|
|
104
|
-
blocked_action.period_check.should == expected_blocked_action.period_check
|
|
105
|
-
blocked_action.timestamp.should == expected_blocked_action.timestamp
|
|
106
|
-
end
|
|
107
|
-
end
|
|
82
|
+
expected_rate_limit = Pause::RateLimitedEvent.new(action, action.checks[0], 7, time.to_i)
|
|
108
83
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
MyNotification.disable
|
|
115
|
-
|
|
116
|
-
action.analyze.should be_nil
|
|
84
|
+
rate_limit.should be_a(Pause::RateLimitedEvent)
|
|
85
|
+
rate_limit.identifier.should == expected_rate_limit.identifier
|
|
86
|
+
rate_limit.sum.should == expected_rate_limit.sum
|
|
87
|
+
rate_limit.period_check.should == expected_rate_limit.period_check
|
|
88
|
+
rate_limit.timestamp.should == expected_rate_limit.timestamp
|
|
117
89
|
end
|
|
118
90
|
end
|
|
119
91
|
end
|
|
@@ -131,16 +103,16 @@ describe Pause::Action do
|
|
|
131
103
|
end
|
|
132
104
|
end
|
|
133
105
|
|
|
134
|
-
describe "#
|
|
106
|
+
describe "#rate_limited_identifiers" do
|
|
135
107
|
it "should return all the identifiers blocked" do
|
|
136
|
-
action.increment!(Time.now.to_i
|
|
137
|
-
other_action.increment!(Time.now.to_i
|
|
108
|
+
action.increment!(100, Time.now.to_i)
|
|
109
|
+
other_action.increment!(100, Time.now.to_i)
|
|
138
110
|
|
|
139
111
|
action.ok?
|
|
140
112
|
other_action.ok?
|
|
141
113
|
|
|
142
|
-
MyNotification.
|
|
143
|
-
MyNotification.
|
|
114
|
+
MyNotification.rate_limited_identifiers.should include(action.identifier)
|
|
115
|
+
MyNotification.rate_limited_identifiers.should include(other_action.identifier)
|
|
144
116
|
end
|
|
145
117
|
end
|
|
146
118
|
|
|
@@ -153,11 +125,11 @@ describe Pause::Action do
|
|
|
153
125
|
other_action.ok?
|
|
154
126
|
|
|
155
127
|
MyNotification.tracked_identifiers.should include(action.identifier, other_action.identifier)
|
|
156
|
-
MyNotification.
|
|
128
|
+
MyNotification.rate_limited_identifiers.should == [action.identifier]
|
|
157
129
|
|
|
158
130
|
MyNotification.unblock_all
|
|
159
131
|
|
|
160
|
-
MyNotification.
|
|
132
|
+
MyNotification.rate_limited_identifiers.should be_empty
|
|
161
133
|
MyNotification.tracked_identifiers.should == [other_action.identifier]
|
|
162
134
|
end
|
|
163
135
|
end
|
|
@@ -174,9 +146,13 @@ describe Pause::Action, ".check" do
|
|
|
174
146
|
check 300, 150, 200
|
|
175
147
|
end
|
|
176
148
|
|
|
149
|
+
class ActionWithHashChecks < Pause::Action
|
|
150
|
+
check period_seconds: 50, block_ttl: 60, max_allowed: 100
|
|
151
|
+
end
|
|
152
|
+
|
|
177
153
|
it "should define a period check on new instances" do
|
|
178
154
|
ActionWithCheck.new("id").checks.should == [
|
|
179
|
-
Pause::PeriodCheck.new(100, 150, 200)
|
|
155
|
+
Pause::PeriodCheck.new(100, 150, 200)
|
|
180
156
|
]
|
|
181
157
|
end
|
|
182
158
|
|
|
@@ -188,6 +164,12 @@ describe Pause::Action, ".check" do
|
|
|
188
164
|
]
|
|
189
165
|
end
|
|
190
166
|
|
|
167
|
+
it "should accept hash arguments" do
|
|
168
|
+
ActionWithHashChecks.new("id").checks.should == [
|
|
169
|
+
Pause::PeriodCheck.new(50, 100, 60)
|
|
170
|
+
]
|
|
171
|
+
end
|
|
172
|
+
|
|
191
173
|
end
|
|
192
174
|
|
|
193
175
|
describe Pause::Action, ".scope" do
|
data/spec/pause/analyzer_spec.rb
CHANGED
|
@@ -37,7 +37,7 @@ describe Pause::Analyzer do
|
|
|
37
37
|
describe "#analyze" do
|
|
38
38
|
it "checks and blocks if max_allowed is reached" do
|
|
39
39
|
time = Time.now
|
|
40
|
-
adapter.should_receive(:
|
|
40
|
+
adapter.should_receive(:rate_limit!).once.with(action.key, 12)
|
|
41
41
|
Timecop.freeze time do
|
|
42
42
|
5.times do
|
|
43
43
|
analyzer.increment(action)
|
|
@@ -57,7 +57,7 @@ describe Pause::Analyzer do
|
|
|
57
57
|
5.times do
|
|
58
58
|
analyzer.increment(action)
|
|
59
59
|
end
|
|
60
|
-
analyzer.check(action).should be_a(Pause::
|
|
60
|
+
analyzer.check(action).should be_a(Pause::RateLimitedEvent)
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
end
|
|
@@ -53,7 +53,7 @@ describe Pause::Redis::Adapter do
|
|
|
53
53
|
let(:ttl) { 110000 }
|
|
54
54
|
|
|
55
55
|
it "saves ip to redis with expiration" do
|
|
56
|
-
adapter.
|
|
56
|
+
adapter.rate_limit!(key, ttl)
|
|
57
57
|
redis_conn.get(blocked_key).should_not be_nil
|
|
58
58
|
redis_conn.ttl(blocked_key).should == ttl
|
|
59
59
|
end
|
|
@@ -65,8 +65,8 @@ describe Pause::Redis::Adapter do
|
|
|
65
65
|
let(:ttl) { 110000 }
|
|
66
66
|
|
|
67
67
|
it "should return true if blocked" do
|
|
68
|
-
adapter.
|
|
69
|
-
(!!redis_conn.get(blocked_key).should) == adapter.
|
|
68
|
+
adapter.rate_limit!(key, ttl)
|
|
69
|
+
(!!redis_conn.get(blocked_key).should) == adapter.rate_limited?(key)
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
data/spec/spec_helper.rb
CHANGED
|
@@ -9,8 +9,7 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
|
|
9
9
|
require 'rubygems'
|
|
10
10
|
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
|
11
11
|
require 'pause'
|
|
12
|
-
|
|
13
|
-
Dir['spec/support/**/*.rb'].each { |filename| require_relative "../#{filename}" }
|
|
12
|
+
require 'support/fakeredis'
|
|
14
13
|
|
|
15
14
|
RSpec.configure do |config|
|
|
16
15
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pause
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.4
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Atasay Gokkaya
|
|
9
9
|
- Paul Henry
|
|
10
|
-
- Eric
|
|
10
|
+
- Eric Saxby
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
@@ -122,6 +122,7 @@ files:
|
|
|
122
122
|
- .pairs
|
|
123
123
|
- .rspec
|
|
124
124
|
- .rvmrc
|
|
125
|
+
- .travis.yml
|
|
125
126
|
- Gemfile
|
|
126
127
|
- Guardfile
|
|
127
128
|
- LICENSE.txt
|
|
@@ -130,9 +131,9 @@ files:
|
|
|
130
131
|
- lib/pause.rb
|
|
131
132
|
- lib/pause/action.rb
|
|
132
133
|
- lib/pause/analyzer.rb
|
|
133
|
-
- lib/pause/blocked_action.rb
|
|
134
134
|
- lib/pause/configuration.rb
|
|
135
135
|
- lib/pause/helper/timing.rb
|
|
136
|
+
- lib/pause/rate_limited_event.rb
|
|
136
137
|
- lib/pause/redis/adapter.rb
|
|
137
138
|
- lib/pause/version.rb
|
|
138
139
|
- pause.gemspec
|
|
@@ -173,4 +174,3 @@ test_files:
|
|
|
173
174
|
- spec/pause/redis/adapter_spec.rb
|
|
174
175
|
- spec/spec_helper.rb
|
|
175
176
|
- spec/support/fakeredis.rb
|
|
176
|
-
has_rdoc:
|