Current section

Files

Jump to
pi_bridge lib pi mirror quack_db lifecycle.ex
Raw

lib/pi/mirror/quack_db/lifecycle.ex

defmodule Pi.Mirror.QuackDB.Lifecycle do
@moduledoc false
use GenServer
alias Pi.Mirror.QuackDB, as: Mirror
def ensure_started do
with {:ok, pid} <- ensure_process(), do: GenServer.call(pid, :ensure_started, 30_000)
end
def status do
case Process.whereis(__MODULE__) do
nil -> %{status: :stopped}
pid -> GenServer.call(pid, :status)
end
end
def stop do
case Process.whereis(__MODULE__) do
nil -> :ok
pid -> GenServer.stop(pid, :normal, 10_000)
end
catch
:exit, _reason -> :ok
end
def start_link(_opts \\ []), do: GenServer.start(__MODULE__, %{}, name: __MODULE__)
@impl true
def init(state), do: {:ok, state}
@impl true
def handle_call(:ensure_started, _from, %{resources: resources} = state) do
if resources_alive?(resources) do
{:reply, {:ok, resources}, state}
else
start_resources(state)
end
end
def handle_call(:ensure_started, _from, state), do: start_resources(state)
def handle_call(:status, _from, %{resources: resources} = state) do
{:reply, %{status: :ready, resources: resources}, state}
end
def handle_call(:status, _from, state), do: {:reply, %{status: :stopped}, state}
@impl true
def terminate(_reason, %{resources: %{supervisor: supervisor}}) do
if Process.alive?(supervisor), do: Supervisor.stop(supervisor)
:ok
catch
:exit, _reason -> :ok
end
def terminate(_reason, _state), do: :ok
defp start_resources(state) do
case Mirror.start_mirror_resources() do
{:ok, resources} -> {:reply, {:ok, resources}, Map.put(state, :resources, resources)}
{:error, reason} -> {:reply, {:error, reason}, Map.put(state, :error, reason)}
end
end
defp resources_alive?(%{supervisor: supervisor, conn: conn}) do
Process.alive?(supervisor) and connection_alive?(conn)
end
defp resources_alive?(_resources), do: false
defp connection_alive?(conn) do
match?(:ok, QuackDB.ping(conn, timeout: 1_000))
catch
:exit, _reason -> false
end
defp ensure_process do
case Process.whereis(__MODULE__) do
nil ->
case start_link([]) do
{:ok, pid} -> {:ok, pid}
{:error, {:already_started, pid}} -> {:ok, pid}
error -> error
end
pid ->
{:ok, pid}
end
end
end