Current section
Files
Jump to
Current section
Files
lib/codex/runtime/erlexec.ex
defmodule Codex.Runtime.Erlexec do
@moduledoc """
Unified erlexec startup shared across subprocess modules.
"""
@exec_wait_attempts 20
@exec_wait_delay_ms 50
@spec ensure_started() :: :ok | {:error, term()}
def ensure_started do
with :ok <- ensure_application_started() do
ensure_exec_worker()
end
end
defp ensure_application_started do
case Application.ensure_all_started(:erlexec) do
{:ok, _} -> :ok
{:error, {:already_started, _}} -> :ok
{:error, {:erlexec, {:already_started, _}}} -> :ok
{:error, reason} -> {:error, reason}
end
end
defp ensure_exec_worker do
case wait_for_exec_worker(@exec_wait_attempts) do
:ok ->
:ok
:error ->
recover_missing_exec_worker()
end
end
defp recover_missing_exec_worker do
if exec_app_alive?() do
{:error, :exec_not_running}
else
with :ok <- restart_application(),
:ok <- wait_for_exec_worker(@exec_wait_attempts) do
:ok
else
:error -> {:error, :exec_not_running}
{:error, _} = error -> error
end
end
end
defp wait_for_exec_worker(0) do
if exec_worker_alive?(), do: :ok, else: :error
end
defp wait_for_exec_worker(attempts_remaining) when attempts_remaining > 0 do
if exec_worker_alive?() do
:ok
else
Process.sleep(@exec_wait_delay_ms)
wait_for_exec_worker(attempts_remaining - 1)
end
end
defp restart_application do
case Application.stop(:erlexec) do
:ok -> ensure_application_started()
{:error, {:not_started, :erlexec}} -> ensure_application_started()
{:error, {:not_started, _app}} -> ensure_application_started()
{:error, reason} -> {:error, reason}
end
end
defp exec_worker_alive? do
case Process.whereis(:exec) do
pid when is_pid(pid) -> Process.alive?(pid)
_ -> false
end
end
defp exec_app_alive? do
case Process.whereis(:exec_app) do
pid when is_pid(pid) -> Process.alive?(pid)
_ -> false
end
end
end