Class: Pause::Action
- Inherits:
-
Object
- Object
- Pause::Action
- Defined in:
- lib/pause/action.rb
Class Attribute Summary collapse
-
.checks ⇒ Object
Returns the value of attribute checks.
Instance Attribute Summary collapse
-
#identifier ⇒ Object
Returns the value of attribute identifier.
Class Method Summary collapse
- .adapter ⇒ Object
-
.check(*args, **opts) ⇒ Object
Action subclasses should define their checks as follows.
- .disable ⇒ Object
- .disabled? ⇒ Boolean
-
.enable ⇒ Object
Actions can be globally disabled or re-enabled in a persistent way.
- .enabled? ⇒ Boolean
- .inherited(klass) ⇒ Object
- .rate_limited_identifiers ⇒ Object
- .tracked_identifiers ⇒ Object
- .unblock_all ⇒ Object
Instance Method Summary collapse
- #analyze(recalculate: false) ⇒ Object
- #block_for(ttl) ⇒ Object
- #checks ⇒ Object
- #if_rate_limited {|check_result| ... } ⇒ Object
- #increment!(count = 1, timestamp = Time.now.to_i) ⇒ Object
-
#initialize(identifier) ⇒ Action
constructor
A new instance of Action.
- #ok? ⇒ Boolean
- #rate_limited? ⇒ Boolean
- #scope ⇒ Object
- #unblock ⇒ Object
- #unless_rate_limited(count: 1, timestamp: Time.now.to_i, &_block) ⇒ Object
Constructor Details
#initialize(identifier) ⇒ Action
Returns a new instance of Action.
5 6 7 8 |
# File 'lib/pause/action.rb', line 5 def initialize(identifier) @identifier = identifier self.class.checks ||= [] end |
Class Attribute Details
.checks ⇒ Object
Returns the value of attribute checks.
15 16 17 |
# File 'lib/pause/action.rb', line 15 def checks @checks end |
Instance Attribute Details
#identifier ⇒ Object
Returns the value of attribute identifier.
3 4 5 |
# File 'lib/pause/action.rb', line 3 def identifier @identifier end |
Class Method Details
.check(*args, **opts) ⇒ Object
Action subclasses should define their checks as follows
period_seconds - compare all activity by an identifier within the time period
max_allowed - if the number of actions by an identifier exceeds max_allowed for the time period marked
by period_seconds, it is no longer ok.
block_ttl - time to mark identifier as not ok
class MyAction < Pause::Action
check period_seconds: 60, max_allowed: 100, block_ttl: 3600
check period_seconds: 1800, max_allowed: 2000, block_ttl: 3600
end
76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/pause/action.rb', line 76 def check(*args, **opts) self.checks ||= [] params = if args.empty? # if block_ttl is not provided, just default to the period opts[:block_ttl] ||= opts[:period_seconds] [opts[:period_seconds], opts[:max_allowed], opts[:block_ttl]] else args end self.checks << Pause::PeriodCheck.new(*params) end |
.disable ⇒ Object
52 53 54 |
# File 'lib/pause/action.rb', line 52 def disable adapter.disable(scope) end |
.disabled? ⇒ Boolean
60 61 62 |
# File 'lib/pause/action.rb', line 60 def disabled? !enabled? end |
.enable ⇒ Object
Actions can be globally disabled or re-enabled in a persistent way.
MyAction.disable
MyAction.enabled? => false
MyAction.disabled? => true
MyAction.enable
MyAction.enabled? => true
MyAction.disabled? => false
48 49 50 |
# File 'lib/pause/action.rb', line 48 def enable adapter.enable(scope) end |
.enabled? ⇒ Boolean
56 57 58 |
# File 'lib/pause/action.rb', line 56 def enabled? adapter.enabled?(scope) end |
.inherited(klass) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/pause/action.rb', line 17 def inherited(klass) klass.instance_eval do # Action subclasses should define their scope as follows # # class MyAction < Pause::Action # scope "my:scope" # end # @scope = klass.name.downcase.gsub(/::/, '.') class << self # @param [String] args def scope(*args) @scope = args.first if args && args.size == 1 @scope end end end end |
.rate_limited_identifiers ⇒ Object
95 96 97 |
# File 'lib/pause/action.rb', line 95 def rate_limited_identifiers adapter.rate_limited_keys(scope) end |
.tracked_identifiers ⇒ Object
91 92 93 |
# File 'lib/pause/action.rb', line 91 def tracked_identifiers adapter.all_keys(scope) end |
.unblock_all ⇒ Object
99 100 101 |
# File 'lib/pause/action.rb', line 99 def unblock_all adapter.delete_rate_limited_keys(scope) end |
Instance Method Details
#analyze(recalculate: false) ⇒ Object
146 147 148 |
# File 'lib/pause/action.rb', line 146 def analyze(recalculate: false) Pause.analyzer.check(self, recalculate: recalculate) end |
#block_for(ttl) ⇒ Object
127 128 129 |
# File 'lib/pause/action.rb', line 127 def block_for(ttl) adapter.rate_limit!(scope, identifier, ttl) end |
#checks ⇒ Object
123 124 125 |
# File 'lib/pause/action.rb', line 123 def checks self.class.checks end |
#if_rate_limited {|check_result| ... } ⇒ Object
118 119 120 121 |
# File 'lib/pause/action.rb', line 118 def if_rate_limited(&_block) check_result = analyze(recalculate: true) yield(check_result) unless check_result.nil? end |
#increment!(count = 1, timestamp = Time.now.to_i) ⇒ Object
131 132 133 |
# File 'lib/pause/action.rb', line 131 def increment!(count = 1, = Time.now.to_i) adapter.increment(scope, identifier, , count) end |
#ok? ⇒ Boolean
139 140 141 142 143 144 |
# File 'lib/pause/action.rb', line 139 def ok? Pause.analyzer.check(self).nil? rescue ::Redis::CannotConnectError => e Pause::Logger.fatal "Error connecting to redis: #{e.inspect} #{e.} #{e.backtrace.join("\n")}" false end |
#rate_limited? ⇒ Boolean
135 136 137 |
# File 'lib/pause/action.rb', line 135 def rate_limited? !ok? end |
#scope ⇒ Object
10 11 12 |
# File 'lib/pause/action.rb', line 10 def scope self.class.scope end |
#unblock ⇒ Object
150 151 152 |
# File 'lib/pause/action.rb', line 150 def unblock adapter.delete_rate_limited_key(scope, identifier) end |
#unless_rate_limited(count: 1, timestamp: Time.now.to_i, &_block) ⇒ Object
108 109 110 111 112 113 114 115 116 |
# File 'lib/pause/action.rb', line 108 def unless_rate_limited(count: 1, timestamp: Time.now.to_i, &_block) check_result = analyze if check_result.nil? yield increment!(count, ) else check_result end end |