breaker v0.1.0 Breaker.Agent

Maintains the state for a particular circuit breaker.

This Agent holds the constantly changing state properties of the circuit and the information required to calculate those.

Summary

Types

t()

Complex map holding a circuit’s state

Functions

Recalculates if the given Breaker.Agent state should be open or closed

Count a response in the current bucket of the window

Count a hit (sucessful request) in the current window and sums of the passed Map

Count a miss (error) in the current window and the sum of the passed Map

Check if the circuit is open (broken)

Calculate if the circuit should be open or closed

Reset an open breaker

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

Roll the calculation window for the given Breaker.Agent.t

Start a new circuit breaker state holder

Manually trip the circuit, setting it to an “open” status

Types

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

Complex map holding a circuit’s state.

Includes the current state, error_threshold, and counts.

Functions

calculate_status(state)
calculate_status(Breaker.Agent.t) :: Breaker.Agent.t

Recalculates if the given Breaker.Agent state should be open or closed.

Checks the total number of requests and errors in the rolling window and trips the circuit if it’s higher than error_threshold.

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

Count a response in the current bucket of the window.

Parameters:

  • circuit: The Agent containing the circuit’s state.
  • response: The received %HTTPotion.Response{}

Examples:

iex> window = [%{total: 0, errors: 0}]
iex> {:ok, circuit} = Breaker.Agent.start_link(%{window: window})
iex> Breaker.Agent.count(circuit, %HTTPotion.Response{status_code: 200})
:ok

iex> window = [%{total: 1, errors: 0}]
iex> {:ok, circuit} = Breaker.Agent.start_link(%{window: window})
iex> Breaker.Agent.count(circuit, %HTTPotion.Response{status_code: 500})
:ok

iex> window = [%{total: 0, errors: 0}, %{total: 2, errors: 1}]
iex> {:ok, circuit} = Breaker.Agent.start_link(%{window: window})
iex> Breaker.Agent.count(circuit, %HTTPotion.Response{status_code: 200})
:ok
count_hit(circuit)

Count a hit (sucessful request) in the current window and sums of the passed Map.

Examples:

iex> circuit = %{window: [%{total: 0, errors: 0}], sum: %{total: 0, errors: 0}}
iex> Breaker.Agent.count_hit(circuit)
%{window: [%{total: 1, errors: 0}], sum: %{total: 1, errors: 0}}
count_miss(circuit)

Count a miss (error) in the current window and the sum of the passed Map.

Examples:

iex> circuit = %{window: [%{total: 0, errors: 0}], sum: %{total: 0, errors: 0}}
iex> Breaker.Agent.count_miss(circuit)
%{window: [%{total: 1, errors: 1}], sum: %{total: 1, errors: 1}}
open?(circuit)
open?(pid) :: boolean

Check if the circuit is open (broken).

Parameters:

  • circuit: The Agent containing the circuit’s state.

Examples:

iex> {:ok, circuit} = Breaker.Agent.start_link(%{open: false})
iex> Breaker.Agent.open?(circuit)
false

iex> {:ok, circuit} = Breaker.Agent.start_link(%{open: true})
iex> Breaker.Agent.open?(circuit)
true
recalculate(circuit)
recalculate(pid) :: :ok

Calculate if the circuit should be open or closed.

Parameters:

  • circuit: The Agent containing the circuit’s state.

Examples:

iex> sum = %{total: 10, errors: 10}
iex> options = %{error_threshold: 0.05, sum: sum, open: false}
iex> {:ok, circuit} = Breaker.Agent.start_link(options)
iex> Breaker.Agent.open?(circuit)
false
iex> Breaker.Agent.recalculate(circuit)
iex> Breaker.Agent.open?(circuit)
true
reset(circuit)
reset(pid) :: :ok

Reset an open breaker.

Parameters:

  • circuit: The Agent containing the circuit’s state.

Examples:

iex> {:ok, circuit} = Breaker.Agent.start_link(%{open: true})
iex> Breaker.Agent.reset(circuit)
iex> Breaker.Agent.open?(circuit)
false

iex> {:ok, circuit} = Breaker.Agent.start_link(%{open: false})
iex> Breaker.Agent.reset(circuit)
iex> Breaker.Agent.open?(circuit)
false
roll(circuit)
roll(pid) :: :ok

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

Parameters:

  • circuit: The Agent containing the circuit’s state.

Examples:

iex> options = %{window: [%{total: 1, errors: 0}]}
iex> {:ok, circuit} = Breaker.Agent.start_link(options)
iex> Breaker.Agent.roll(circuit)
:ok
roll_window(state)

Roll the calculation window for the given Breaker.Agent.t.

This creates a new current bucket, pushing the existing ones down the line, potentially removes the oldest one (if window_length has been reached), and recalculates the status of the breaker.

start_link(options \\ %{})
start_link(%{}) :: {:ok, pid}

Start a new circuit breaker state holder.

The internal state looks like the following:

%{
  open: false,
  error_threshold: 0.05,
  window_length: 10,
  bucket_length: 1000,
  sum: %{
    total: 0,
    errors: 0
  },
  window: [
    %{
      total: 0,
      errors: 0
    },
    ...
  ]
}

Parameters:

  • options: An options map. It should contain the following keys:

    • open: A boolean indicating if the circuit is open or not.
  • 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.

Examples:

iex> {:ok, circuit} = Breaker.Agent.start_link(%{misses: 0})
iex> is_pid(circuit)
true
trip(circuit)
trip(pid) :: :ok

Manually trip the circuit, setting it to an “open” status.

Paramaters:

  • circuit: The Agent containing the circuit’s state.

Examples:

iex> {:ok, circuit} = Breaker.Agent.start_link(%{open: false})
iex> Breaker.Agent.trip(circuit)
iex> Breaker.Agent.open?(circuit)
true

iex> {:ok, circuit} = Breaker.Agent.start_link(%{open: true})
iex> Breaker.Agent.trip(circuit)
iex> Breaker.Agent.open?(circuit)
true