I have run into an issue while testing a simple Phoenix channel and using Phoenix.Presence.
It looks to me like the tests completes and the Presence process notices that a user has disconnected as a result. It then attempts to fetch the new user list but at that point the database connection has already been closed for that test. Is there any way to handle this sort of situation?
I tried calling Presence.unlink
from within the test but was unable to get any other results.
I’m seeing the following error:
09:32:22.414 [error] Task #PID<0.580.0> started from MyApp.Presence terminating
** (stop) exited in: GenServer.call(#PID<0.577.0>, {:checkout, #Reference<0.0.5.2491>, true, 15000}, 5000)
** (EXIT) shutdown: "owner #PID<0.576.0> exited while client #PID<0.579.0> is still running with: shutdown"
(db_connection) lib/db_connection/ownership/proxy.ex:32: DBConnection.Ownership.Proxy.checkout/2
(db_connection) lib/db_connection.ex:919: DBConnection.checkout/2
(db_connection) lib/db_connection.ex:741: DBConnection.run/3
(db_connection) lib/db_connection.ex:584: DBConnection.prepare_execute/4
(ecto) lib/ecto/adapters/postgres/connection.ex:80: Ecto.Adapters.Postgres.Connection.prepare_execute/5
(ecto) lib/ecto/adapters/sql.ex:243: Ecto.Adapters.SQL.sql_call/6
(ecto) lib/ecto/adapters/sql.ex:431: Ecto.Adapters.SQL.execute_and_cache/7
(ecto) lib/ecto/repo/queryable.ex:130: Ecto.Repo.Queryable.execute/5
(ecto) lib/ecto/repo/queryable.ex:35: Ecto.Repo.Queryable.all/4
(my_app) lib/my_app/presence.ex:17: MyApp.Presence.fetch/2
(phoenix) lib/phoenix/presence.ex:199: anonymous fn/5 in Phoenix.Presence.handle_diff/5
(stdlib) lists.erl:1263: :lists.foldl/3
(phoenix) lib/phoenix/presence.ex:197: anonymous fn/4 in Phoenix.Presence.handle_diff/5
(elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Function: #Function<1.96140178/0 in Phoenix.Presence.handle_diff/5>
Args: []
Using this channel module:
defmodule MyApp.ExampleChannel do
use MyApp.Web, :channel
def join(_channel_name, _params, socket) do
send self(), :after_join
{:ok, socket}
end
def handle_info(:after_join, socket) do
current_user = socket.assigns.current_user
{:ok, _} = Presence.track(socket, current_user.id, %{})
{:noreply, socket}
end
end
this presence module:
defmodule MyApp.Presence do
import Ecto.Query
alias MyApp.User
alias MyApp.Repo
use Phoenix.Presence, otp_app: :MyApp,
pubsub_server: MyApp.PubSub
def fetch(_topic, entries) do
query =
from u in User,
where: u.id in ^Map.keys(entries),
select: {u.id, u}
users = query |> Repo.all |> Enum.into(%{})
for { key, %{ metas: metas } } <- entries, into: %{} do
int_key = String.to_integer(key)
{ key, %{ metas: metas, user: users[int_key] } }
end
end
end
and this channel test:
defmodule MyApp.ExampleChannelTest do
use MyApp.ChannelCase
alias MyApp.ExampleChannel
test 'example' do
user = create_a_user
params = %{ current_user: user }
{:ok, _, socket} = subscribe_and_join(socket("", params), ExampleChannel, "control")
end
end
Any help is greatly appreciated. Thanks!