Class: Cognizant::Process::Triggers::Flapping

Inherits:
Trigger
  • Object
show all
Defined in:
lib/cognizant/process/triggers/flapping.rb

Constant Summary collapse

TRIGGER_STATES =
[:starting, :restarting]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Flapping


12
13
14
15
16
17
18
19
20
# File 'lib/cognizant/process/triggers/flapping.rb', line 12

def initialize(options = {})
  @times       = options[:times]       || 5
  @within      = options[:within]      || 1
  @retry_after = options[:retry_after] || 5
  @retries     = options[:retries]     || 0

  @timeline = Util::RotationalArray.new(@times)
  @num_of_tries = 0
end

Instance Attribute Details

#retriesObject

Returns the value of attribute retries


9
10
11
# File 'lib/cognizant/process/triggers/flapping.rb', line 9

def retries
  @retries
end

#retry_afterObject

Returns the value of attribute retry_after


9
10
11
# File 'lib/cognizant/process/triggers/flapping.rb', line 9

def retry_after
  @retry_after
end

#timelineObject (readonly)

Returns the value of attribute timeline


10
11
12
# File 'lib/cognizant/process/triggers/flapping.rb', line 10

def timeline
  @timeline
end

#timesObject

Returns the value of attribute times


9
10
11
# File 'lib/cognizant/process/triggers/flapping.rb', line 9

def times
  @times
end

#withinObject

Returns the value of attribute within


9
10
11
# File 'lib/cognizant/process/triggers/flapping.rb', line 9

def within
  @within
end

Instance Method Details

#can_retry?Boolean


38
39
40
41
42
43
# File 'lib/cognizant/process/triggers/flapping.rb', line 38

def can_retry?
  # retry_after = 0 means do not retry.
  self.retry_after > 0 and
  # retries = 0 means always retry.
  (self.retries == 0 or (self.retries > 0 and @num_of_tries <= self.retries))
end

#check_flappingObject


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/cognizant/process/triggers/flapping.rb', line 45

def check_flapping
  # The process has not flapped if we haven't encountered enough incidents.
  return unless (@timeline.compact.length == self.times)

  # Check if the incident happend within the timeframe.
  if within_duration?
    @num_of_tries += 1

    Log[self].debug "Flapping detected (##{@num_of_tries}) for #{@delegate.process.name}(pid:#{@delegate.process.cached_pid})."

    # 0.1 to ensure the state isn't randomly caught in throw :halt below.
    @delegate.schedule_event(:unmonitor, [0.1, self.retry_after].min)
    @delegate.schedule_event(:start, self.retry_after) if can_retry?

    @timeline.clear

    # This will prevent a transition from happening in the process state_machine.
    throw :halt
  end
end

#notify(transition) ⇒ Object


22
23
24
25
26
27
# File 'lib/cognizant/process/triggers/flapping.rb', line 22

def notify(transition)
  if TRIGGER_STATES.include?(transition.to_name)
    self.timeline << Time.now.to_i
    self.check_flapping
  end
end

#reset!Object


29
30
31
32
# File 'lib/cognizant/process/triggers/flapping.rb', line 29

def reset!
  @timeline.clear
  @num_of_tries = 0
end

#within_duration?Boolean


34
35
36
# File 'lib/cognizant/process/triggers/flapping.rb', line 34

def within_duration?
  (@timeline.last - @timeline.first) <= self.within
end