Current section

Files

Jump to
step_flow lib step_flow repo checker.ex
Raw

lib/step_flow/repo/checker.ex

defmodule StepFlow.Repo.Checker do
@moduledoc false
use GenServer
require Logger
@registry_table :repo_status
@entry_name :is_up
def child_spec(_) do
%{
id: StepFlow.Repo.Checker,
start: {StepFlow.Repo.Checker, :start_link, []},
type: :worker
}
end
def start_link do
GenServer.start_link(__MODULE__, false, name: __MODULE__)
end
def get_repo_status do
GenServer.call(__MODULE__, :pop)
end
def repo_running? do
case :ets.whereis(@registry_table) do
:undefined ->
:timer.sleep(1000)
repo_running?()
_tid ->
:ets.lookup(@registry_table, @entry_name)
|> Keyword.get(@entry_name)
end
end
@impl true
def init(is_repo_up) do
Logger.warn("[#{__MODULE__}] Start checking repo status...")
_status = :ets.new(@registry_table, [:named_table, :set, :protected, read_concurrency: true])
is_repo_up = check_repo_status(is_repo_up)
{:ok, is_repo_up}
end
@impl true
def handle_info(:check, is_repo_up) do
Logger.debug("[#{__MODULE__}] Check the repo status.")
# Schedule once more
is_repo_up = check_repo_status(is_repo_up)
{:noreply, is_repo_up}
end
@impl true
def handle_info(:kill_me, state) do
{:stop, :normal, state}
end
@impl true
def handle_call(:pop, _from, status) do
Logger.debug("[#{__MODULE__}] Get repo status...")
is_repo_up = repo_running?()
{:reply, is_repo_up, status}
end
defp check_repo_status(was_previously_up) do
hostname =
StepFlow.Configuration.get_var_value(StepFlow.Repo, :hostname)
|> String.to_charlist()
port = to_integer(StepFlow.Configuration.get_var_value(StepFlow.Repo, :port))
is_repo_up =
case :gen_tcp.connect(hostname, port, [:binary, active: false], 1000) do
{:ok, socket} ->
:gen_tcp.close(socket)
true
{:error, :econnrefused} ->
false
{:error, error} ->
Logger.warn("Unexpected error on database connection check: #{inspect(error)}")
false
end
:ets.insert(@registry_table, {@entry_name, is_repo_up})
if is_repo_up do
if !was_previously_up do
if Process.whereis(StepFlow.Amqp.Supervisor) != nil do
StepFlow.Amqp.Supervisor.start_children()
end
if Process.whereis(StepFlow.ProcessManager) != nil do
StepFlow.ProcessManager.start_children()
end
end
else
if was_previously_up do
StepFlow.Amqp.Supervisor.stop_children()
StepFlow.ProcessManager.stop_children()
end
end
Process.send_after(self(), :check, 500)
is_repo_up
end
defp to_integer(int) when is_integer(int) do
int
end
defp to_integer(str) do
String.to_integer(str)
end
end