DBConnection.ConnectionError when testing channels with Phoenix Presence

I’ve been building the follow-along Rumbl app while reading the Programming Phoenix book and ran into some issues testing my channels. When running the tests I get the following output:

07:31:35.021 [error] Postgrex.Protocol (#PID<0.331.0>) disconnected: ** (DBConnection.ConnectionError) owner #PID<0.665.0> exited

Client #PID<0.668.0> is still using a connection from owner at location:

    :prim_inet.send_recv_reply/2
    (postgrex 0.15.7) lib/postgrex/protocol.ex:2918: Postgrex.Protocol.do_send/3
    (postgrex 0.15.7) lib/postgrex/protocol.ex:1858: Postgrex.Protocol.rebind_execute/4
    (ecto_sql 3.4.5) lib/ecto/adapters/sql/sandbox.ex:370: Ecto.Adapters.SQL.Sandbox.Connection.proxy/3
    (db_connection 2.3.0) lib/db_connection/holder.ex:316: DBConnection.Holder.holder_apply/4
    (db_connection 2.3.0) lib/db_connection.ex:1254: DBConnection.run_execute/5
    (db_connection 2.3.0) lib/db_connection.ex:1341: DBConnection.run/6
    (db_connection 2.3.0) lib/db_connection.ex:595: DBConnection.execute/4
    (ecto_sql 3.4.5) lib/ecto/adapters/postgres/connection.ex:80: Ecto.Adapters.Postgres.Connection.execute/4
    (ecto_sql 3.4.5) lib/ecto/adapters/sql.ex:544: Ecto.Adapters.SQL.execute!/4
    (ecto_sql 3.4.5) lib/ecto/adapters/sql.ex:526: Ecto.Adapters.SQL.execute/5
    (ecto 3.4.6) lib/ecto/repo/queryable.ex:192: Ecto.Repo.Queryable.execute/4
    (ecto 3.4.6) lib/ecto/repo/queryable.ex:17: Ecto.Repo.Queryable.all/3
    (rumbl_web 0.1.0) lib/rumbl_web/channels/presence.ex:16: RumblWeb.Presence.fetch/2
    (phoenix 1.5.7) lib/phoenix/presence.ex:365: anonymous fn/4 in Phoenix.Presence.Tracker.handle_diff/2
    (stdlib 3.13) maps.erl:233: :maps.fold_1/3
    (phoenix 1.5.7) lib/phoenix/presence.ex:363: anonymous fn/3 in Phoenix.Presence.Tracker.handle_diff/2
    (elixir 1.10.4) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (stdlib 3.13) proc_lib.erl:226: :proc_lib.init_p_do_apply/3

The connection itself was checked out by #PID<0.668.0> at location:

    (ecto_sql 3.4.5) lib/ecto/adapters/postgres/connection.ex:80: Ecto.Adapters.Postgres.Connection.execute/4
    (ecto_sql 3.4.5) lib/ecto/adapters/sql.ex:544: Ecto.Adapters.SQL.execute!/4
    (ecto_sql 3.4.5) lib/ecto/adapters/sql.ex:526: Ecto.Adapters.SQL.execute/5
    (ecto 3.4.6) lib/ecto/repo/queryable.ex:192: Ecto.Repo.Queryable.execute/4
    (ecto 3.4.6) lib/ecto/repo/queryable.ex:17: Ecto.Repo.Queryable.all/3
    (rumbl_web 0.1.0) lib/rumbl_web/channels/presence.ex:16: RumblWeb.Presence.fetch/2
    (phoenix 1.5.7) lib/phoenix/presence.ex:365: anonymous fn/4 in Phoenix.Presence.Tracker.handle_diff/2
    (stdlib 3.13) maps.erl:233: :maps.fold_1/3
    (phoenix 1.5.7) lib/phoenix/presence.ex:363: anonymous fn/3 in Phoenix.Presence.Tracker.handle_diff/2
    (elixir 1.10.4) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (stdlib 3.13) proc_lib.erl:226: :proc_lib.init_p_do_apply/3

The docs propose this solution for writing tests in a project that uses Phoenix Presence. I have added the code snippet, but I’m still getting the same errors when running my channel tests.

The setup block of my channel_case.ex (including the snippet from the Docs) looks like this:

`setup tags do
    :ok = Ecto.Adapters.SQL.Sandbox.checkout(Rumbl.Repo)

    unless tags[:async] do
      Ecto.Adapters.SQL.Sandbox.mode(Rumbl.Repo, {:shared, self()})
    end

    on_exit(fn ->
      for pid <- RumblWeb.Presence.fetchers_pids() do
        ref = Process.monitor(pid)
        assert_receive {:DOWN, ^ref, _, _, _}, 1000
      end
    end)

    :ok
  end`

I’ve tried adding the timer, as suggested in this PR as well, to no avail.

Any help would be appreciated. Thanks!

1 Like

How is your test setup? Are you using the style described in this comment?

Hey, thanks for the quick reply. I originally haven’t added the start_owner / stop_owner calls, but now I have. Sometimes the tests work flawlessly now but I’m still getting errors most of the time.

I’m using ecto_sql 3.4.6. The project is an umbrella project with rumbl, rumbl_web and info_sys as apps in it. Here’s my setup block from the channel_case.ex in the rumbl_web app - This should be as described in the comment you mentioned:

setup tags do
    pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Rumbl.Repo, shared: not tags[:async])
    on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)

    on_exit(fn ->
      for pid <- RumblWeb.Presence.fetchers_pids() do
        ref = Process.monitor(pid)
        assert_receive {:DOWN, ^ref, _, _, _}, 1000
      end
    end)

    :ok
  end

And here’s the error I’m getting now:

19:37:26.568 [error] Task #PID<0.686.0> started from RumblWeb.Presence_shard0 terminating
** (stop) exited in: DBConnection.Holder.checkout(#PID<0.679.0>, [log: #Function<9.29328868/1 in Ecto.Adapters.SQL.with_log/3>, source: "users", timeout: 15000, pool_size: 10, pool: DBConnection.Ownership])
    ** (EXIT) shutdown: "owner #PID<0.678.0> exited"
    (db_connection 2.3.0) lib/db_connection/holder.ex:86: DBConnection.Holder.checkout/2
    (db_connection 2.3.0) lib/db_connection/holder.ex:67: DBConnection.Holder.checkout/2
    (db_connection 2.3.0) lib/db_connection.ex:1028: DBConnection.checkout/3
    (db_connection 2.3.0) lib/db_connection.ex:1339: DBConnection.run/6
    (db_connection 2.3.0) lib/db_connection.ex:595: DBConnection.execute/4
    (ecto_sql 3.4.5) lib/ecto/adapters/postgres/connection.ex:80: Ecto.Adapters.Postgres.Connection.execute/4
    (ecto_sql 3.4.5) lib/ecto/adapters/sql.ex:544: Ecto.Adapters.SQL.execute!/4
    (ecto_sql 3.4.5) lib/ecto/adapters/sql.ex:526: Ecto.Adapters.SQL.execute/5
    (ecto 3.4.6) lib/ecto/repo/queryable.ex:192: Ecto.Repo.Queryable.execute/4
    (ecto 3.4.6) lib/ecto/repo/queryable.ex:17: Ecto.Repo.Queryable.all/3
    (rumbl_web 0.1.0) lib/rumbl_web/channels/presence.ex:16: RumblWeb.Presence.fetch/2
    (phoenix 1.5.7) lib/phoenix/presence.ex:365: anonymous fn/4 in Phoenix.Presence.Tracker.handle_diff/2
    (stdlib 3.13) maps.erl:233: :maps.fold_1/3
    (phoenix 1.5.7) lib/phoenix/presence.ex:363: anonymous fn/3 in Phoenix.Presence.Tracker.handle_diff/2
    (elixir 1.10.4) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (stdlib 3.13) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Function: #Function<0.87329413/0 in Phoenix.Presence.Tracker.handle_diff/2>
    Args: []
2 Likes

I know it has been two years, but it might help someone else along the way. I had the same issue while following “programming phoenix >= 1.4” and…

Looks like the snippet above was inserted in apps/rumbl/test/data_case.ex, but when I put it in apps/rumbl_web/test/support/channel_case.ex is fixes the issue.

As an Elixir/Phoenix noob I can’t explain why or is it even the right way to fix the issue… but it works.