A Faraday Middleware to handle spotty web services.
Add this line to your application's Gemfile:
gem 'faraday_middleware-circuit_breaker'
And then execute:
$ bundle
Or install it yourself as:
$ gem install faraday_middleware-circuit_breaker
Simply add the middleware:
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker
end
Middleware will automatically attempt to recover after a certain amount of time. This timeout is customizable:
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, timeout: 10
end
The default is 60
seconds. To disable automatic recovery, set the timeout to Float::INFINITY
. To make automatic recovery
instantaneous, set the timeout to 0
seconds though it's not recommended.
Some services might be allowed to fail more or less frequently than others. You can configure this by setting a custom threshold:
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, threshold: 5
end
The default is 3
times.
On a failure, middleware will render an empty 503
http response by default. You can customize the fallback response:
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, fallback: ->(env, exception) { # do something }
end
Middleware will try to call the call
method on fallback
passing 2 arguments:
env
-- the connection environement from faradayexception
-- the exception raised that triggered the circuit breaker
You can pass a method to be eager called like this:
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, fallback: method(:foo)
end
def foo(env, exception)
# do something
end
Whatever you chose, your method should return a valid faraday response. For example, here is the default fallback implementation:
proc { Faraday::Response.new(status: 503, response_headers: {}) }
In some situations, it might required to allow for particular error types to be exempt from tripping the circuit breaker
(like regular 403 or 401 HTTP responses, which aren't really out-of-the-ordinary conditions that should trip the circuit breaker).
The underlying stoplight gem supports custom error handling,
The error_handler
option allows you to add your own customer error handler behavior:
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, error_handler: ->(exception, handler) { # do something }
end
Middleware will try to call the call
method on error_handler
passing 2 arguments:
exception
-- the exception raised that triggered the circuit breakerhandler
-- the current error handlerProc
that would be in charge of handling theexception
if noerror_handler
option was passed
You can pass a method to be eager called like this (with a handler that exempts ArgumentError
from tripping the circuit):
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, error_handler: method(:foo)
end
def foo(exception, handler)
raise exception if exception.is_a?(ArgumentError)
handler.call(exception)
end
NOTE: It is most always a good idea to call the original handler
with the exception that was passed in at the end of your
handler. (By default, the error_handler
will just be Stoplight::Default::ERROR_HANDLER
)
Middleware send notifications to standard error by default. You can customize the receivers.
To send notifications to a logger:
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, notifiers: { logger: Rails.logger }
end
To send notifications to honeybadger:
require 'honeybadger'
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, notifiers: { honeybadger: "api_key" }
end
You'll need to have Honeybadger gem installed.
To send notifications to slack:
require 'slack-notifier'
slack = Slack::Notifier.new('http://www.example.com/webhook-url')
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, notifiers: { slack: slack }
end
You'll need to have Slack gem installed.
To send notifications to hipchat:
require 'hipchat'
hip_chat = HipChat::Client.new('token')
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, notifiers: { hipchat: { client: hipchat, room: 'room' } }
end
You'll need to have HipChat gem installed.
To send notifications to bugsnag:
require 'bugsnag'
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, notifiers: { bugsnag: Bugsnag }
end
You'll need to have Bugsnag gem installed.
To send notifications to sentry:
require 'sentry-raven'
sentry_raven = Raven::Configuration.new
Faraday.new(url: 'http://foo.com') do |c|
c.use :circuit_breaker, notifiers: { sentry: sentry_raven } # or { raven: sentry_raven }
end
You'll need to have Sentry gem installed.
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/faraday_middleware-circuit_breaker.
The gem is available as open source under the terms of the MIT License.