Hi,
I am trying migrate a small game I wrote to LiveView. However, I am stuck since multiple hours and can’t figure out why the GenServer processes I create seem to die instantly.
I have an Agent module called Global which maintains a Map of Game (GenServer) processes:
defmodule Fakeartist.Global do
use Agent
...
def games do
Agent.get(__MODULE__, &(&1))
end
def new_game(player_name, player_id, num_rounds) do
...
{:ok, game} = Game.start_link(player_name, player_id, num_rounds)
Agent.update(__MODULE__, &Map.put_new(&1, token, game))
{:ok, token, game}
end
end
Currently, without LIveView, I do this to create a game inside a controller:
defmodule FakeartistWeb.GameController do
...
def create(conn, %{"user" => %{"num_rounds" => num_rounds}}) do
...
{:ok, token, _} = Global.new_game(username, get_session(conn, :user_id), num_rounds)
conn
|> redirect(to: Routes.game_path(conn, :show, token))
end
end
It works perfectly, I can retrieve the Game process, call functions on it and so in.
Now I tried to implement the same with LiveViews:
index.html.leex:
<button phx-click="addgame">Create</button>
...
<%= for {token, game} <- @games do %>
<td><%= token %></td>
<td><%= length(Game.get_players(game)) %></td>
<% end %>
index.ex:
defmodule FakeartistWeb.GameLive.Index do
...
@impl true
def mount(_params, _session, socket) do
socket = socket
|> assign(:games, fetch_games())
{:ok, socket}
end
@impl true
def handle_event("addgame", params, socket) do
IO.puts("addgame: #{inspect params}")
{:ok, token, game} = Global.new_game("some_username", "some_user_id", 2)
IO.puts("addgame: #{inspect Game.props(game)}")
IO.puts("addgame: #{inspect Global.games[token]}")
socket = socket
|> assign(:games, fetch_games())
|> push_redirect(to: "/livegame")
{:noreply, socket}
end
defp fetch_games do
Global.games()
end
As soon as I click the button, the new Game process is created which can observed in the log:
addgame: %{<...>}
addgame: %{category: :none, current_player: :none, <...>}
addgame: #PID<0.473.0>
This shows the pid and that I am able to call methods on it. However, as soon as the view tries to display the game list, it crashes:
** (stop) exited in: GenServer.call(#PID<0.473.0>, :get_players, 5000)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
The game was added to the map in Global, but the process that the map entry is referring to and which was still running in the handle_event call seems to have died now.
I have no clue why, is there something I am missing?
I appreciate any help. I tried to reduce the code as much as possible, hope its understandable.
Thanks
Felix