Current section

Files

Jump to
islands_engine lib islands engine proxy.ex
Raw

lib/islands/engine/proxy.ex

defmodule Islands.Engine.Proxy do
@moduledoc """
Runs function `GenServer.call` on behalf of module `Islands.Engine`
while providing increased fault-tolerance capability.
"""
alias __MODULE__.{Error, GameNotStarted, Info}
alias IO.ANSI.Plus, as: ANSI
alias Islands.Engine.Game.{Server, Tally}
alias Islands.Engine
@timeout 10
@times 5
@spec call(tuple, String.t()) :: Tally.t() | :ok
def call(request, game_name) do
game_name |> Server.via() |> GenServer.call(request)
catch
:exit, reason ->
Error.log(:exit, reason)
wait_and_call(request, game_name, reason)
end
@spec stop(atom, String.t()) :: :ok
def stop(reason, game_name) do
game_name |> Server.via() |> GenServer.stop(reason)
catch
:exit, exit_reason ->
Error.log(:exit, exit_reason)
wait_and_stop(reason, game_name, exit_reason)
end
## Private functions
@spec wait_and_call(tuple, String.t(), term) :: Tally.t() | :ok
defp wait_and_call(request, game_name, reason) do
game_name |> wait(reason, @times) |> Server.via() |> GenServer.call(request)
catch
:exit, reason ->
Error.log(:exit, reason)
game_name |> GameNotStarted.message() |> ANSI.puts()
end
@spec wait_and_stop(atom, String.t(), term) :: :ok
defp wait_and_stop(reason, game_name, exit_reason) do
game_name
|> wait(exit_reason, @times)
|> Server.via()
|> GenServer.stop(reason)
catch
:exit, exit_reason ->
Error.log(:exit, exit_reason)
game_name |> GameNotStarted.message() |> ANSI.puts()
end
# On restarts, wait if name not yet registered...
@spec wait(String.t(), term, non_neg_integer) :: String.t()
defp wait(game_name, _reason, 0), do: game_name
defp wait(game_name, reason, times_left) do
Info.log(:game_not_registered, game_name, @timeout, times_left, reason)
Process.sleep(@timeout)
case Engine.game_pid(game_name) do
pid when is_pid(pid) ->
Info.log(:game_registered, game_name, pid, times_left, reason)
game_name
nil ->
wait(game_name, reason, times_left - 1)
end
end
end