## Vert.x Circuit Breaker

Vert.x Circuit Breaker is an implementation of the Circuit Breaker pattern for Vert.x.

It keeps track of the number of failures and open the circuit when a threshold is reached. Optionally, a fallback is executed.

Supported failures are:

- failures reported by your code in a `Future`

- exception thrown by your code

- uncompleted futures (timeout)

Operations guarded by a circuit breaker are intended to by non-blocking and asynchronous in order to benefits from the Vert.x execution model.

## Using the vert.x circuit breaker

To use the Vert.x Circuit Breaker, add the following dependency to the dependencies section of your build descriptor:

- Maven (in your `pom.xml`):

    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-circuit-breaker</artifactId>
      <version>3.3.0</version>
    </dependency>

- Gradle (in your `build.gradle` file):

    compile 'io.vertx:vertx-circuit-breaker:3.3.0'

## Using the circuit breaker

To use the circuit breaker you need to:

1. Create a circuit breaker, with the configuration you want (timeout, number of failure before opening the circuit)

2. Execute some code using the breaker

Here is an example:

    require 'vertx-circuit-breaker/circuit_breaker'
    breaker = VertxCircuitBreaker::CircuitBreaker.create("my-circuit-breaker", vertx, {
      'maxFailures' => 5,
      'timeout' => 2000,
      'fallbackOnFailure' => true,
      'resetTimeout' => 10000
    })

    breaker.execute() { |future|
      # some code executing with the breaker
      # the code reports failures or success on the given future.
      # if this future is marked as failed, the breaker increased the
      # number of failures
    }.set_handler() { |ar_err,ar|
      # Get the operation result.
    }

The executed block receives a `Future` object as parameter, to denote the success or failure of the operation as well as the result. For example in the following example, the result is the output of a REST endpoint invocation:

    require 'vertx-circuit-breaker/circuit_breaker'
    breaker = VertxCircuitBreaker::CircuitBreaker.create("my-circuit-breaker", vertx, {
      'maxFailures' => 5,
      'timeout' => 2000
    })

    breaker.execute() { |future|
      vertx.create_http_client().get_now(8080, "localhost", "/") { |response|
        if (response.status_code() != 200)
          future.fail("HTTP error")
        else
          response.exception_handler(&future.method(:fail)).body_handler() { |buffer|
            future.complete(buffer.to_string())
          }
        end
      }
    }.set_handler() { |ar_err,ar|
      # Do something with the result
    }

The result of the operation is provided using the:

- returned `Future` when calling `execute` methods

- provided `Future` when calling the `executeAndReport` methods

Optionally, you can provide a fallback executed when the circuit is open:

    require 'vertx-circuit-breaker/circuit_breaker'
    breaker = VertxCircuitBreaker::CircuitBreaker.create("my-circuit-breaker", vertx, {
      'maxFailures' => 5,
      'timeout' => 2000
    })

    breaker.execute_with_fallback(lambda { |future|
      vertx.create_http_client().get_now(8080, "localhost", "/") { |response|
        if (response.status_code() != 200)
          future.fail("HTTP error")
        else
          response.exception_handler(&future.method(:fail)).body_handler() { |buffer|
            future.complete(buffer.to_string())
          }
        end
      }
    }, lambda { |v|
      # Executed when the circuit is opened
      return "Hello"
    }).set_handler() { |ar_err,ar|
      # Do something with the result
    }

The fallback is called whenever the circuit is open, or if the `isFallbackOnFailure` is enabled. When a fallback is set, the result is using the output of the fallback function. The fallback function takes as parameter a `Throwable` object and returned an object of the expected type.

The fallback can also be set on the `CircuitBreaker` object directly:

    require 'vertx-circuit-breaker/circuit_breaker'
    breaker = VertxCircuitBreaker::CircuitBreaker.create("my-circuit-breaker", vertx, {
      'maxFailures' => 5,
      'timeout' => 2000
    }).fallback(lambda { |v|
      # Executed when the circuit is opened.
      return "hello"
    })

    breaker.execute() { |future|
      vertx.create_http_client().get_now(8080, "localhost", "/") { |response|
        if (response.status_code() != 200)
          future.fail("HTTP error")
        else
          response.exception_handler(&future.method(:fail)).body_handler() { |buffer|
            future.complete(buffer.to_string())
          }
        end
      }
    }

## Callbacks

You can also configures callbacks invoked when the circuit is opened or closed:

    require 'vertx-circuit-breaker/circuit_breaker'
    breaker = VertxCircuitBreaker::CircuitBreaker.create("my-circuit-breaker", vertx, {
      'maxFailures' => 5,
      'timeout' => 2000
    }).open_handler() { |v|
      puts "Circuit opened"
    }.close_handler() { |v|
      puts "Circuit closed"
    }

    breaker.execute() { |future|
      vertx.create_http_client().get_now(8080, "localhost", "/") { |response|
        if (response.status_code() != 200)
          future.fail("HTTP error")
        else
          # Do something with the response
          future.complete()
        end
      }
    }

You can also be notified when the circuit breaker decide to attempt to reset (half-open state). You can register such as callback with `halfOpenHandler`.

## Event bus notification

Every time the circuit state changes, an event is published on the event bus. The address on which the event are sent is configurable with `notificationAddress`. If `null` is passed to this method, the notifications are disabled. By default, the used address is `vertx.circuit-breaker`.

Each event contains a Json Object with:

- `state` : the new circuit breaker state (`OPEN`, `CLOSED`, `HALF_OPEN`)

- `name` : the name of the circuit breaker

- `failures` : the number of failures

- `node` : the identifier of the node (`local` is Vert.x is not running in cluster mode)

## The half-open state

When the circuit is “open,” calls to the circuit breaker fail immediately, without any attempt to execute the real operation. After a suitable amount of time (configured from `resetTimeout`, the circuit breaker decides that the operation has a chance of succeeding, so it goes into the `half-open` state. In this state, the next call to the circuit breaker is allowed to execute the dangerous operation. Should the call succeed, the circuit breaker resets and returns to the `closed` state, ready for more routine operation. If this trial call fails, however, the circuit breaker returns to the `open` state until another timeout elapses.