breaker v1.0.0 Breaker

A circuit-breaker wrapped around HTTPotion to make requests to external resources and help your application gracefully fail.

Defines a function for each HTTP method (ie Breaker.get()) that returns a Task that will execute the HTTP request (using HTTPotion) and record the response in the circuit breaker.

Summary

Types

t()

A Map containing information for the circuit

Functions

Count a given response in the breaker’s current bucket and sums

Make an async DELETE request to the specified path using the given breaker

Checks if the given response is either a %Breaker.OpenCircuitError{}, a timeout, or has a 500 status code

Make an async GET request to the specified path using the given breaker

Make an async HEAD request to the specified path using the given breaker

Make an HTTP(S) request using the specified breaker, using the given method

Ask if the circuit is open or not

Make an async OPTIONS request to the specified path using the given breaker

Make an async PATCH request to the specified path using the given breaker

Make an async POST request to the specified path using the given breaker

Make an async PUT request to the specified path using the given breaker

Reset the circuit breaker

Roll the window, creating a new bucket and possibly pushing out an old one, updating the sum values as necessary

Create a new circuit-breaker with the given options keyword list

Trip the circuit

Types

t()
t() :: %{url: String.t, headers: [...], timeout: number, open: boolean, error_threshold: float, window_length: number, bucket_length: number, sum: %{total: number, errors: number}, window: [%{total: number, errors: number}]}

A Map containing information for the circuit.

It holds:

  • url: The base url associated with the breaker.
  • headers: Additional headers to use when making requests.
  • timeout: The time to wait (in ms) before giving up on a request.
  • open: The current state of the breaker.
  • error_threshold: The percent of requests allowed to fail, as a float.
  • window_length: The number of buckets in the health calculation window.
  • bucket_length: The number of milliseconds for each bucket.
  • sum: The current sum of total requests and errors.
  • window: The window of buckets adding up to sum.

Functions

count(circuit, response)
count(pid, %HTTPotion.Response{body: term, headers: term, status_code: term} | %HTTPotion.ErrorResponse{message: term}) :: :ok

Count a given response in the breaker’s current bucket and sums.

Adds the response to the current bucket of the health window, the total sum, and finalizes by recalculating the breaker’s status.

You probably won’t need to use this manually.

This is done automatically when a request is made through this module.

Parameters:

  • circuit: The pid of the breaker to count in.
  • response: The response received from a request.

Examples:

iex> {:ok, circuit} = Breaker.start_link([url: "http://httpbin.org/"])
iex> Breaker.count(circuit, %HTTPotion.ErrorResponse{})
:ok
delete(circuit, path, options \\ [])
delete(pid, String.t, []) :: Task.t

Make an async DELETE request to the specified path using the given breaker.

Task returning alias for make_request(circuit, path, :delete, options).

Parameters:

  • circuit: The breaker to perform the request.
  • path: The path string to append to the end of the breaker’s url.
  • options: Additional options passed to HTTPotion.
error?(response)
error?(%Breaker.OpenCircuitError{message: term} | %HTTPotion.ErrorResponse{message: term} | %HTTPotion.Response{body: term, headers: term, status_code: term}) :: boolean

Checks if the given response is either a %Breaker.OpenCircuitError{}, a timeout, or has a 500 status code.

Parameters:

  • response: The response recieved from one of the HTTP method calls.

Examples:

iex> Breaker.error?(%Breaker.OpenCircuitError{})
true

iex> Breaker.error?(%HTTPotion.ErrorResponse{})
true

iex> Breaker.error?(%HTTPotion.Response{status_code: 500})
true

iex> Breaker.error?(%HTTPotion.Response{status_code: 200})
false
get(circuit, path, options \\ [])
get(pid, String.t, []) :: Task.t

Make an async GET request to the specified path using the given breaker.

Task returning alias for make_request(circuit, path, :get, options).

Parameters:

  • circuit: The breaker to perform the request.
  • path: The path string to append to the end of the breaker’s url.
  • options: Additional options passed to HTTPotion.

Examples:

iex> {:ok, breaker} = Breaker.start_link([url: "http://httpbin.org/"])
iex> request = Breaker.get(breaker, "/get")
iex> response = Task.await(request)
iex> response.status_code
200
head(circuit, path, options \\ [])
head(pid, String.t, []) :: Task.t

Make an async HEAD request to the specified path using the given breaker.

Task returning alias for make_request(circuit, path, :head, options).

Parameters:

  • circuit: The breaker to perform the request.
  • path: The path string to append to the end of the breaker’s url.
  • options: Additional options passed to HTTPotion.
make_request(circuit, path, method, options \\ [])
make_request(pid, String.t, atom, []) ::
  %HTTPotion.Response{body: term, headers: term, status_code: term} |
  %HTTPotion.ErrorResponse{message: term} |
  %Breaker.OpenCircuitError{message: term}

Make an HTTP(S) request using the specified breaker, using the given method.

This function isn’t probably one you would want to use on your own and instead, use the method-specific functions (Breaker.get()). They return Tasks and are async, while this is sync.

Parameters:

  • circuit: The circuit to make the request with.
  • path: The request path, this is add to the circuit’s url.
  • method: An atom specifying the HTTP method, used by HTTPotion.
  • options: Extra options to pass to HTTPotion. The circuit’s timeout and headers are also added to this.

Examples:

iex> {:ok, breaker} = Breaker.start_link([url: "http://httpbin.org/"])
iex> response = Breaker.make_request(breaker, "/get", :get)
iex> response.status_code
200
open?(circuit)
open?(pid) :: boolean

Ask if the circuit is open or not.

Don’t forget, an open circuit is one that is not properly connected and thus does not allow electrons to flow. In this case, it does not allow communication to the external resource. I get this mixed up in my head sometimes.

Parameters:

  • circuit: The pid of the breaker to check.

Examples:

iex> options = [url: "http://httpbin.org/"]
iex> {:ok, circuit} = Breaker.start_link(options)
iex> Breaker.open?(circuit)
false
options(circuit, path, options \\ [])
options(pid, String.t, []) :: Task.t

Make an async OPTIONS request to the specified path using the given breaker.

Task returning alias for make_request(circuit, path, :options, options).

Parameters:

  • circuit: The breaker to perform the request.
  • path: The path string to append to the end of the breaker’s url.
  • options: Additional options passed to HTTPotion.
patch(circuit, path, options \\ [])
patch(pid, String.t, []) :: Task.t

Make an async PATCH request to the specified path using the given breaker.

Task returning alias for make_request(circuit, path, :patch, options).

Parameters:

  • circuit: The breaker to perform the request.
  • path: The path string to append to the end of the breaker’s url.
  • options: Additional options passed to HTTPotion.
post(circuit, path, options \\ [])
post(pid, String.t, []) :: Task.t

Make an async POST request to the specified path using the given breaker.

Task returning alias for make_request(circuit, path, :post, options).

Parameters:

  • circuit: The breaker to perform the request.
  • path: The path string to append to the end of the breaker’s url.
  • options: Additional options passed to HTTPotion.
put(circuit, path, options \\ [])
put(pid, String.t, []) :: Task.t

Make an async PUT request to the specified path using the given breaker.

Task returning alias for make_request(circuit, path, :put, options).

Parameters:

  • circuit: The breaker to perform the request.
  • path: The path string to append to the end of the breaker’s url.
  • options: Additional options passed to HTTPotion.
reset(circuit)
reset(pid) :: :ok

Reset the circuit breaker.

This sets the “open” status to false and has no effect if the “open” status is already false.

This has the effect of restoring communications using the circuit, but it does not clear any recent unhealthy requests. As such, it could recalculate and trip itself again at the end of the next request or after a roll.

Parameters:

  • circuit: The pid of the breaker to reset.

Examples:

iex> options = [url: "http://httpbin.org/", open: true]
iex> {:ok, circuit} = Breaker.start_link(options)
iex> Breaker.open?(circuit)
true
iex> Breaker.reset(circuit)
iex> Breaker.open?(circuit)
false
roll(circuit)
roll(pid) :: :ok

Roll the window, creating a new bucket and possibly pushing out an old one, updating the sum values as necessary.

Parameters:

  • circuit: The pid of the breaker to roll.

Examples:

iex> options = [url: "http://httpbin.org/", window: [%{total: 1, errors: 0}]]
iex> {:ok, circuit} = Breaker.start_link(options)
iex> Breaker.roll(circuit)
:ok
start_link(options, name \\ nil)
start_link([{:url, String.t}], atom | tuple) :: {:ok, pid}

Create a new circuit-breaker with the given options keyword list.

Parameters:

  • options: A Keyword list of options, described below.
  • name: The name to register the GenServer.

Available options are:

  • url: The base url to use for the breaker. This is ideally a single external resource, complete with protocal, domain name, port, and an optional subpath. Required.
  • headers: A keyword list of headers, passed to HTTPotion.
  • timeout: How long to wait until considering the request timed out. Passed to HTTPotion.
  • open: Boolean defining if the circuit is broken. Defaults to false.
  • error_threshold: The percent of requests allowed to fail, as a float. Defaults to 0.05 (5%)
  • window_length: The number of buckets in the health calculation window. Defaults to 10.
  • bucket_length: The number of milliseconds for each bucket. Defaults to 1000, meaning health is caluculated over the past 10 seconds using the defaults.

Examples:

iex> options = [url: "http://httpbin.org/"]
iex> {:ok, circuit} = Breaker.start_link(options)
iex> is_pid(circuit)
true
trip(circuit)
trip(pid) :: :ok

Trip the circuit.

This sets the “open” status to true and has no effect if the “open” status is already true.

This has the effect of cutting off communications using the circuit and starts the restoration process to test if the external source is healthy.

Parameters

  • circuit: The pid of the breaker to trip.

Examples:

iex> {:ok, circuit} = Breaker.start_link([url: "http://httpbin.org/"])
iex> response = Breaker.get(circuit, "/get") |> Task.await
iex> response.status_code
200
iex> Breaker.trip(circuit)
iex> Breaker.get(circuit, "/get") |> Task.await
%Breaker.OpenCircuitError{message: "circuit is open"}