Class: Pause::Action

Inherits:
Object
  • Object
show all
Defined in:
lib/pause/action.rb

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

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

.checksObject

Returns the value of attribute checks.



15
16
17
# File 'lib/pause/action.rb', line 15

def checks
  @checks
end

Instance Attribute Details

#identifierObject

Returns the value of attribute identifier.



3
4
5
# File 'lib/pause/action.rb', line 3

def identifier
  @identifier
end

Class Method Details

.adapterObject



103
104
105
# File 'lib/pause/action.rb', line 103

def adapter
  Pause.adapter
end

.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

.disableObject



52
53
54
# File 'lib/pause/action.rb', line 52

def disable
  adapter.disable(scope)
end

.disabled?Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/pause/action.rb', line 60

def disabled?
  !enabled?
end

.enableObject

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

Returns:

  • (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_identifiersObject



95
96
97
# File 'lib/pause/action.rb', line 95

def rate_limited_identifiers
  adapter.rate_limited_keys(scope)
end

.tracked_identifiersObject



91
92
93
# File 'lib/pause/action.rb', line 91

def tracked_identifiers
  adapter.all_keys(scope)
end

.unblock_allObject



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

#checksObject



123
124
125
# File 'lib/pause/action.rb', line 123

def checks
  self.class.checks
end

#if_rate_limited {|check_result| ... } ⇒ Object

Yields:

  • (check_result)


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, timestamp = Time.now.to_i)
  adapter.increment(scope, identifier, timestamp, count)
end

#ok?Boolean

Returns:

  • (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.message} #{e.backtrace.join("\n")}"
  false
end

#rate_limited?Boolean

Returns:

  • (Boolean)


135
136
137
# File 'lib/pause/action.rb', line 135

def rate_limited?
  !ok?
end

#scopeObject



10
11
12
# File 'lib/pause/action.rb', line 10

def scope
  self.class.scope
end

#unblockObject



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, timestamp)
  else
    check_result
  end
end