README.md
# Supervision
[![Gem Version](https://badge.fury.io/rb/supervision.svg)][gem]
[![Build Status](https://secure.travis-ci.org/piotrmurach/supervision.svg?branch=master)][travis]
[![Code Climate](https://codeclimate.com/github/piotrmurach/supervision/badges/gpa.svg)][codeclimate]
[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/supervision/badge.svg)][coverage]
[![Inline docs](http://inch-ci.org/github/piotrmurach/supervision.svg?branch=master)][inchpages]
[gem]: http://badge.fury.io/rb/supervision
[travis]: http://travis-ci.org/piotrmurach/supervision
[codeclimate]: https://codeclimate.com/github/piotrmurach/supervision
[coverage]: https://coveralls.io/github/piotrmurach/supervision
[inchpages]: http://inch-ci.org/github/piotrmurach/supervision
> 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:
```ruby
@supervision = Supervision.new { |arg| remote_api_call(arg) }
```
or alternatively use `supervise` helper
```ruby
@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:
```ruby
@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:
```ruby
Supervision.supervise_as(:danger) { remote_api_call }
```
In order to retrieve registered circuit you can use hash syntax:
```ruby
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:
```ruby
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.
```ruby
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:
```ruby
@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
```ruby
@supervision = Supervison.new max_failures: 2, call_timeout: 10.milli, reset_timeout: 0.1.sec do
remote_api_call
end
```
or use `configure` helper
```ruby
@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**
```ruby
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.