/supervision

Write distributed systems that are resilient and self-heal.

Primary LanguageRubyMIT LicenseMIT

Supervision

Gem Version Build Status Code Climate Coverage Status Inline docs

Write distributed systems that are resilient and self-heal. Remote calls can fail or hang indefinietly without a response. Supervision will help to isolate failure and keep individual components from bringing down the whole system. The basic idea is to wrap dangerous method call inside protected supervise helper that will monitor for failure and handle it according to the specified rules to prevent it from cascading.

Installation

Add this line to your application's Gemfile:

gem 'supervision'

And then execute:

$ bundle

Or install it yourself as:

$ gem install supervision

1 Usage

Supervision instance takes the following configuration options:

  • :max_failure - maximum failure count allowed before Supervision raises CircuitBreakerOpenError. By default 5 failures are allowed.
  • :call_timeout - duration time for a method before it is assumed to have failed. By default 10 milliseconds.
  • :reset_timeout - duration before a method is allowed to attempt a call. Subsequent calls will fail fast if failure is detected. By default 100 milliseconds

Next to instantiate the Supervision in order to protect a call to external/remote service that has potential to fail do:

@supervision = Supervision.new { |arg| remote_api_call(arg) }

or alternatively use supervise helper

@supervision = Supervision.supervise { |arg| remote_api_call(arg) }

Once the call is wrapped you can execute it by sending call messsage with arguments like so:

@supervision.call({user: 'Piotr'})

2 System

You can register more than one Supervision by using internal register system. Simply register name under which you want the circuit to be available by calling supervise_as helper:

Supervision.supervise_as(:danger) { remote_api_call }

In order to retrieve registered circuit you can use hash syntax:

Supervision[:danger]  # => returns registered circuit

The name under which method is registerd will be available as a method call. Consequently, to execute registered circuit do:

Supervision.danger(:foo, :bar)  # => will call underlying method and pass :foo, :barr

3 Mixin

Supervision can also act as a mixin and expose supervise and supervise_as accordingly. Use supervise_as if you want to be able to register supervised calls inside Supervision system. Otherwise, use supervise helper to create anonymous supervised call.

class Api
  include Supervision

  def remote_call
    ...
  end
  supervise_as :danger { remote_call }  # => register supervision as :danger

  def fetch(repository)
    danger(repository)
  rescue Supervision::CircuitBreakerOpenError
    nil
  end
end

@api = Api.new
@api.fetch('github_api')

4 Callbacks

You can listen for failure and success by attaching on_failure, on_success listeners respectively:

@supervision.on_failure { notify_me }

def notify_me
  puts("The circuit breaker is now open")
end

5 Configuration

If you want to configure Supervision, you can either pass options directly

@supervision = Supervison.new max_failures: 2, call_timeout: 10.milli, reset_timeout: 0.1.sec do
  remote_api_call
end

or use configure helper

@supervision.configure do
  max_failures  5
  call_timeout  10.sec
  reset_timeout 1.min
end

6 Time

All the numeric types are extended with time related helpers to allow for more fluid parameters when creating Supervision

call_timeout: 10.milliseconds
call_timeout: 10.millis
call_timeout: 1.millisecond
call_timeout: 1.milli
call_timeout: 1.second
call_timeout: 1.sec
call_timeout: 10.secs
call_timeout: 10.seconds
call_timeout: 1.minute
call_timeout: 1.min
call_timeout: 10.minutes
call_timeout: 10.mins
call_timeout: 1.hour
call_timeout: 10.hours

Contributing

  1. Fork it ( https://github.com/piotrmurach/supervision/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Copyright

Copyright (c) 2014-2016 Piotr Murach. See LICENSE for further details.