lib/gen_server/proxy/timer.ex

defmodule GenServer.Proxy.Timer do
  use PersistConfig

  alias GenServer.Proxy.Log

  @timeout get_env(:timeout)
  @times get_env(:times)

  @spec wait(GenServer.name()) :: :ok
  def wait(server), do: wait(server, @times)

  ## Private functions

  # On restarts, wait if GenServer was killed or is not yet registered.
  # Note this is an assumption as the GenServer may have never started.
  @spec wait(GenServer.name(), non_neg_integer) :: :ok
  defp wait(_server, 0) do
    :ok
  end

  defp wait(server, times_left) do
    Process.sleep(@timeout)
    times_left = times_left - 1

    case GenServer.whereis(server) do
      # Note there is no guarantee the returned pid is alive, as a
      # process could terminate immediately after it is looked up.
      pid when is_pid(pid) ->
        times = @times - times_left
        now_registered = {server, @timeout, times, pid, __ENV__}
        :ok = Log.warning(:now_registered, now_registered)

      nil ->
        still_unregistered = {server, @timeout, times_left, __ENV__}
        :ok = Log.warning(:still_unregistered, still_unregistered)
        wait(server, times_left)
    end
  end
end