== 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 `link:../../yardoc/Vertx/Future.html[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`):

[source,xml,subs="+attributes"]
----
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-circuit-breaker</artifactId>
  <version>3.3.2</version>
</dependency>
----

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

[source,groovy,subs="+attributes"]
----
compile 'io.vertx:vertx-circuit-breaker:3.3.2'
----

== 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:

[source,ruby]
----
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 `link:../../yardoc/Vertx/Future.html[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:

[source,ruby]
----
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 `link:../../yardoc/Vertx/Future.html[Future]` when calling `execute` methods
* provided `link:../../yardoc/Vertx/Future.html[Future]` when calling the `executeAndReport` methods

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

[source,ruby]
----
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
`link:../dataobjects.html#CircuitBreakerOptions#is_fallback_on_failure-instance_method[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
`link:unavailable[Throwable]` object and returned an object of the expected type.

The fallback can also be set on the `link:../../yardoc/VertxCircuitBreaker/CircuitBreaker.html[CircuitBreaker]` object directly:

[source,ruby]
----
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:

[source,ruby]
----
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 `link:../../yardoc/VertxCircuitBreaker/CircuitBreaker.html#half_open_handler-instance_method[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
`link:../dataobjects.html#CircuitBreakerOptions#set_notification_address-instance_method[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
`link:../dataobjects.html#CircuitBreakerOptions#set_reset_timeout-instance_method[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.


