Skip to content

Commit 1c534e0

Browse files
add check to clear errors on first success if
error_threshold_timeout_enabled false
1 parent 814dac7 commit 1c534e0

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

lib/semian/circuit_breaker.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,14 @@ def mark_failed(error)
7777
end
7878

7979
def mark_success
80-
return unless half_open?
81-
82-
@successes.increment
83-
transition_to_close if success_threshold_reached?
80+
if half_open?
81+
@successes.increment
82+
if success_threshold_reached?
83+
transition_to_close
84+
end
85+
else
86+
@errors.clear unless error_threshold_timeout_enabled
87+
end
8488
end
8589

8690
def reset

test/circuit_breaker_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,17 @@ def test_once_success_threshold_is_reached_only_error_threshold_will_open_the_ci
8787
)
8888
half_open_cicuit!(resource)
8989

90+
STDERR.puts "resource.errors: #{resource.circuit_breaker.instance_variable_get(:@errors).size}"
91+
STDERR.puts "circuit state: #{resource.circuit_breaker.state.value}"
92+
STDERR.puts "error timeout expired: #{resource.circuit_breaker.send(:error_timeout_expired?)}"
93+
9094
assert_circuit_closed(resource)
9195
trigger_error!(resource)
9296

97+
STDERR.puts "resource.errors: #{resource.circuit_breaker.instance_variable_get(:@errors).size}"
98+
STDERR.puts "circuit state: #{resource.circuit_breaker.state.value}"
99+
STDERR.puts "error timeout expired: #{resource.circuit_breaker.send(:error_timeout_expired?)}"
100+
93101
assert_circuit_closed(resource)
94102
trigger_error!(resource)
95103

test/helpers/circuit_breaker_helper.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,24 @@ def trigger_error!(resource = @resource, error = SomeError)
2222

2323
def assert_circuit_closed(resource = @resource)
2424
block_called = false
25+
26+
circuit_breaker = resource.circuit_breaker
27+
28+
old_errors = create_sliding_window_copy(circuit_breaker.instance_variable_get(:@errors))
29+
previously_half_open = circuit_breaker&.send(:half_open?)
30+
2531
resource.acquire { block_called = true }
2632

33+
STDERR.puts "old_errors: #{old_errors.size}"
34+
STDERR.puts "new_errors: #{circuit_breaker.instance_variable_get(:@errors).size}"
35+
36+
unless previously_half_open || circuit_breaker.instance_variable_get(:@error_threshold_timeout_enabled).nil? || circuit_breaker.instance_variable_get(:@error_threshold_timeout_enabled)
37+
circuit_breaker.instance_variable_set(:@errors, old_errors)
38+
end
39+
40+
STDERR.puts "previously_half_open: #{previously_half_open}"
41+
STDERR.puts "error_threshold_timeout_enabled: #{circuit_breaker.instance_variable_get(:@error_threshold_timeout_enabled)}"
42+
2743
assert(block_called, "Expected the circuit to be closed, but it was open")
2844
end
2945

@@ -37,4 +53,21 @@ def assert_circuit_opened(resource = @resource)
3753

3854
assert(open, "Expected the circuit to be open, but it was closed")
3955
end
56+
57+
def create_sliding_window_copy(sliding_window)
58+
return if sliding_window.nil?
59+
60+
implementation_class = sliding_window.class
61+
62+
new_window = implementation_class.new(max_size: sliding_window.max_size)
63+
64+
if sliding_window.respond_to?(:size) && !sliding_window.empty?
65+
original_data = sliding_window.instance_variable_get(:@window)
66+
if original_data.is_a?(Array)
67+
new_window.instance_variable_set(:@window, original_data.dup)
68+
end
69+
end
70+
71+
new_window
72+
end
4073
end

0 commit comments

Comments
 (0)