Created
May 20, 2015 22:33
-
-
Save v-yarotsky/89fdc743a7e17e98f502 to your computer and use it in GitHub Desktop.
CB2 failing test shows that CB2 stays in half-open state forever after opening once
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "spec_helper" | |
require "thread" | |
describe "CB2 acceptance test" do | |
WORKERS = 1 | |
RESPONSE_TIME_SEC = 0.01 | |
def make_breaker(redis) | |
CB2::Breaker.new( | |
service: "test service", | |
strategy: :rolling_window, | |
duration: 3, | |
threshold: 10, # differs from percentage; threshold is an absolute number of failures within window | |
reenable_after: 2, | |
redis: redis | |
) | |
end | |
before do | |
@requests_queue = Queue.new | |
@responses_queue = Queue.new | |
end | |
Request = Struct.new(:action, :duration) | |
it "does all the things" do | |
debug "== normal mode of operation ==" | |
workers = run_workers | |
n = 50 | |
send_n_requests(n, :succeed) | |
assert_equal n, get_n_responses(n).count { |r| r == :succeeded }, "expected #{n} requests to succeed" | |
debug "== failure mode of operation ==" | |
n = 10 | |
send_n_requests(n, :fail) | |
assert_equal n, get_n_responses(n).count { |r| r == :failed }, "expected #{n} requests to fail" | |
debug "== circuit is open ==" | |
n = 50 | |
send_n_requests(n, :succeed) | |
assert_equal n, get_n_responses(n).count { |r| r == :skipped }, "expected #{n} requests to be skipped by circuit breaker" | |
sleep 3 # wait till circuit surely half-closes | |
debug "== resume normal operation ==" | |
send_n_requests(25, :succeed) | |
send_n_requests(5, :fail) | |
send_n_requests(70, :succeed) | |
responses = get_n_responses(100) | |
assert_equal 0, responses.count { |r| r == :skipped }, "expected no requests to be skipped" | |
assert_equal 5, responses.count { |r| r == :failed }, "expected 5 requests to fail" | |
assert_equal 95, responses.count { |r| r == :succeeded }, "expected 20 requests to succeed" | |
workers.each(&:kill) | |
end | |
def send_n_requests(n, action) | |
n.times { @requests_queue.push(Request.new(action, RESPONSE_TIME_SEC)) } | |
end | |
def get_n_responses(n) | |
n.times.map { @responses_queue.pop } | |
end | |
def run_workers | |
WORKERS.times.map do | |
Thread.new(@requests_queue, @responses_queue) do |requests, responses| | |
redis = Redis.new | |
breaker = make_breaker(redis) | |
loop do | |
request = requests.pop | |
begin | |
breaker.run do | |
raise "service unavailable" if request.action == :fail | |
responses.push :succeeded | |
debug "success" | |
end | |
rescue CB2::BreakerOpen | |
responses.push :skipped | |
debug "breaker open" | |
rescue | |
responses.push :failed | |
debug "failure" | |
end | |
sleep request.duration | |
end | |
end | |
end | |
end | |
def debug(msg) | |
puts "[#{Thread.current.object_id}] #{msg}" if ENV["DEBUG"] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment