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 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)
case wait(game_name, reason, @times) do
{:registered, game_name} ->
game_name |> Server.via() |> GenServer.call(request)
{:unregistered, game_name} ->
Info.log(:game_not_started, game_name)
game_name |> GameNotStarted.message() |> IO.puts()
end
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)
case wait(game_name, reason, @times) do
{:registered, game_name} ->
game_name |> Server.via() |> GenServer.stop(reason)
{:unregistered, game_name} ->
Info.log(:game_not_started, game_name)
game_name |> GameNotStarted.message() |> IO.puts()
end
end
## Private functions
# On restarts, wait if name not yet registered...
@spec wait(String.t(), term, non_neg_integer) :: {atom, String.t()}
defp wait(game_name, _reason, 0), do: {:unregistered, 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)
{:registered, game_name}
nil ->
wait(game_name, reason, times_left - 1)
end
end
end