Packages

A simple Elixir package that provides circuit breaker manager

Current section

Files

Jump to
virgil lib manager ets manager.ex
Raw

lib/manager/ets/manager.ex

defmodule Virgil.Manager.ETSManager do
@moduledoc false
use GenServer
require Logger
alias Virgil.Config
@ets_table :circuits
@impl GenServer
def init(_args) do
:ets.new(@ets_table, [:named_table, :public, :set])
case Config.registered_circuits() do
[] ->
nil
nil ->
nil
_ ->
Config.registered_circuits()
|> Enum.map(&{&1, &1.circuit()})
|> Enum.each(&:ets.insert(:circuits, &1))
end
{:ok, %{}}
end
def adapter, do: Virgil.Manager.Ets.Adapter
def start_link(_args),
do: GenServer.start_link(__MODULE__, %{}, name: :ets_manager)
@impl GenServer
def handle_call({:is_closed?, circuit}, _from, state) do
[{_circuit, %{state: circuit_state}}] = :ets.lookup(@ets_table, circuit)
Logger.debug("[#{__MODULE__}] [#{circuit}] Circuit is #{circuit_state}")
{:reply, circuit_state == :closed, state}
end
@impl GenServer
def handle_call({:increment_counter, circuit}, _from, state) do
Logger.debug("[#{__MODULE__}] [#{circuit}] Incrementing error counter")
[{circuit_name, %{failures: current_counter} = circuit}] = :ets.lookup(@ets_table, circuit)
updated_counter = current_counter + 1
:ets.insert(@ets_table, {circuit_name, %{circuit | failures: updated_counter}})
{:reply, {:ok, updated_counter}, state}
end
@impl GenServer
def handle_cast({:close, circuit}, state) do
Logger.debug("[#{__MODULE__}] [#{circuit}] Closing circuit")
circuit_struct = circuit.circuit()
:ets.insert(@ets_table, {circuit, %{circuit_struct | state: :closed, failures: 0}})
{:noreply, state}
end
@impl GenServer
def handle_cast({:open, circuit}, state) do
Logger.debug("[#{__MODULE__}] [#{circuit}] Openning circuit")
circuit_struct = circuit.circuit()
:ets.insert(@ets_table, {circuit, %{circuit_struct | state: :open, failures: 0}})
schedule_circuit_openning(circuit, circuit.reset_timeout())
{:noreply, state}
end
@impl GenServer
def handle_info({:close, circuit}, state) do
Logger.debug("[#{__MODULE__}] [#{circuit}] Closing circuit")
circuit_struct = circuit.circuit()
:ets.insert(@ets_table, {circuit, %{circuit_struct | state: :closed, failures: 0}})
{:noreply, state}
end
defp schedule_circuit_openning(circuit, reset_timeout),
do: Process.send_after(self(), {:close, circuit}, reset_timeout * 1_000)
end