Class: CircuitBreaker::Basic

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

Constant Summary collapse

DEFAULTS =
{
  failure_threshold:    5,
  invocation_timeout:   2,
  reset_timeouts:      10,
  errors_handled:     [],
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Basic

Returns a new instance of Basic.


18
19
20
21
22
23
24
25
26
# File 'lib/circuit_breaker.rb', line 18

def initialize(options = {})
  options             = DEFAULTS.merge(options)
  @failure_threshold  = options[:failure_threshold]
  @invocation_timeout = options[:invocation_timeout]
  @reset_timeouts     = options[:reset_timeouts].is_a?(Proc) ? options[:reset_timeouts] : Array(options[:reset_timeouts])
  @errors_handled     = Array(options[:errors_handled])
  @last_failure_time  = nil
  @failure_count      = 0
end

Instance Attribute Details

#failure_countObject (readonly)

Returns the value of attribute failure_count


16
17
18
# File 'lib/circuit_breaker.rb', line 16

def failure_count
  @failure_count
end

#failure_thresholdObject (readonly)

Returns the value of attribute failure_threshold


16
17
18
# File 'lib/circuit_breaker.rb', line 16

def failure_threshold
  @failure_threshold
end

#last_failure_timeObject (readonly)

Returns the value of attribute last_failure_time


16
17
18
# File 'lib/circuit_breaker.rb', line 16

def last_failure_time
  @last_failure_time
end

Instance Method Details

#closed?Boolean

Returns:

  • (Boolean)

28
29
30
# File 'lib/circuit_breaker.rb', line 28

def closed?
  state == :closed
end

#execute(&block) ⇒ Object


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/circuit_breaker.rb', line 77

def execute &block
  if closed? || half_open?
    begin
      Timeout::timeout(@invocation_timeout) do
        block.call if block_given?
      end
      reset!
    rescue Exception => e
      record_failure if e.class == Timeout::Error || @errors_handled.include?(e.class)
      raise
    end
  else
    raise CircuitBrokenError.new("Circuit is broken")
  end
end

#half_open?Boolean

Returns:

  • (Boolean)

36
37
38
# File 'lib/circuit_breaker.rb', line 36

def half_open?
  state == :half_open
end

#open?Boolean

Returns:

  • (Boolean)

32
33
34
# File 'lib/circuit_breaker.rb', line 32

def open?
  state == :open
end

#record_failureObject


93
94
95
96
# File 'lib/circuit_breaker.rb', line 93

def record_failure
  @failure_count += 1
  @last_failure_time = Time.now
end

#reset!Object


45
46
47
48
# File 'lib/circuit_breaker.rb', line 45

def reset!
  @failure_count     = 0
  @last_failure_time = nil
end

#reset_timeoutObject


54
55
56
57
58
59
60
61
62
# File 'lib/circuit_breaker.rb', line 54

def reset_timeout
  if @reset_timeouts.is_a? Proc
    return @reset_timeouts.call retry_counter
  else
    index = [@reset_timeouts.size - 1, retry_counter].min
    @reset_timeouts[index]
  end

end

#retry_counterObject


50
51
52
# File 'lib/circuit_breaker.rb', line 50

def retry_counter
  @failure_count - @failure_threshold
end

#stateObject


65
66
67
68
69
70
71
72
73
74
75
# File 'lib/circuit_breaker.rb', line 65

def state
  case
    when (@failure_count >= @failure_threshold) &&
      (Time.now - @last_failure_time) > reset_timeout
      :half_open
    when @failure_count >= @failure_threshold
      :open
    else
      :closed
  end
end

#trip!Object


40
41
42
43
# File 'lib/circuit_breaker.rb', line 40

def trip!
  @failure_count = @failure_threshold
  @last_failure_time = Time.now
end