diff --git a/integration_test/ownership/manager_test.exs b/integration_test/ownership/manager_test.exs index a34c73d..962cfa2 100644 --- a/integration_test/ownership/manager_test.exs +++ b/integration_test/ownership/manager_test.exs @@ -681,6 +681,35 @@ defmodule ManagerTest do assert log =~ "** (RuntimeError) oops" end + test "includes label in ownership error when label is provided" do + if function_exported?(:proc_lib, :get_label, 1) do + {:ok, pool, opts} = start_pool(label: TestRepo) + + error = + assert_raise DBConnection.OwnershipError, fn -> + P.run(pool, fn _ -> :ok end, opts) + end + + assert error.message =~ "cannot find ownership process" + assert error.message =~ "using mode :manual" + + assert error.message =~ "(TestRepo)" + end + end + + test "doesn't require a label to produce an ownership error" do + {:ok, pool, opts} = start_pool() + + # Try to use the pool without checking out - should raise OwnershipError + error = + assert_raise DBConnection.OwnershipError, fn -> + P.run(pool, fn _ -> :ok end, opts) + end + + assert error.message =~ "cannot find ownership process" + assert error.message =~ "using mode :manual" + end + defp start_pool(opts \\ []) do stack = [{:ok, :state}] ++ List.duplicate({:idle, :state}, 10) {:ok, agent} = A.start_link(stack) diff --git a/lib/db_connection/ownership/manager.ex b/lib/db_connection/ownership/manager.ex index 482bc7b..8de2678 100644 --- a/lib/db_connection/ownership/manager.ex +++ b/lib/db_connection/ownership/manager.ex @@ -98,6 +98,10 @@ defmodule DBConnection.Ownership.Manager do mode = Keyword.get(pool_opts, :ownership_mode, :auto) checkout_opts = Keyword.take(pool_opts, [:ownership_timeout, :queue_target, :queue_interval]) + if label = pool_opts[:label] do + Util.set_label({__MODULE__, label}) + end + {:ok, %{ pool: pool, @@ -406,9 +410,14 @@ defmodule DBConnection.Ownership.Manager do end defp not_found({pid, _} = from, mode) do + label = Util.pool_label(self()) + label_info = if label, do: "(#{inspect(label)}) ", else: "" + msg = """ cannot find ownership process for #{Util.inspect_pid(pid)} - using mode #{inspect(mode)}. + #{label_info}using mode #{inspect(mode)}. + (Note that a connection's mode reverts to :manual if its owner + terminates.) When using ownership, you must manage connections in one of the four ways: diff --git a/lib/db_connection/util.ex b/lib/db_connection/util.ex index 59d4fb3..e866ec8 100644 --- a/lib/db_connection/util.ex +++ b/lib/db_connection/util.ex @@ -32,12 +32,27 @@ defmodule DBConnection.Util do """ def set_label(label) do if function_exported?(Process, :set_label, 1) do - Process.set_label(label) + apply(Process, :set_label, [label]) else :ok end end + @doc """ + Get the pool label from a pid's process label. + + Returns the label if found, or `nil` otherwise. + Process labels set as `{module, label}` tuples have the label extracted. + """ + def pool_label(pid) when is_pid(pid) do + case get_label(pid) do + {module, label} when is_atom(module) and module != nil and label != nil -> label + _ -> nil + end + end + + def pool_label(_other), do: nil + # Get a process label if `:proc_lib.get_label/1` is available. defp get_label(pid) do if function_exported?(:proc_lib, :get_label, 1) do