Skip to content

Commit 2db46fb

Browse files
authored
Use process labels (#330)
1 parent 68c9271 commit 2db46fb

File tree

6 files changed

+80
-12
lines changed

6 files changed

+80
-12
lines changed

lib/db_connection/connection.ex

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ defmodule DBConnection.Connection do
66
require Logger
77
alias DBConnection.Backoff
88
alias DBConnection.Holder
9+
alias DBConnection.Util
910

1011
@timeout 15_000
1112

@@ -47,6 +48,10 @@ defmodule DBConnection.Connection do
4748
@doc false
4849
@impl :gen_statem
4950
def init({mod, opts, pool, tag}) do
51+
pool_index = Keyword.get(opts, :pool_index)
52+
label = if pool_index, do: "db_conn_#{pool_index}", else: "db_conn"
53+
Util.set_label(label)
54+
5055
s = %{
5156
mod: mod,
5257
opts: opts,
@@ -267,15 +272,19 @@ defmodule DBConnection.Connection do
267272
:no_state,
268273
%{client: {ref, :after_connect}} = s
269274
) do
270-
message = "client #{inspect(pid)} exited: " <> Exception.format_exit(reason)
275+
message =
276+
"client #{Util.inspect_pid(pid)} exited: " <> Exception.format_exit(reason)
277+
271278
err = DBConnection.ConnectionError.exception(message)
272279

273280
{:keep_state, %{s | client: {nil, :after_connect}},
274281
{:next_event, :internal, {:disconnect, {down_log(reason), err}}}}
275282
end
276283

277284
def handle_event(:info, {:DOWN, mon, _, pid, reason}, :no_state, %{client: {ref, mon}} = s) do
278-
message = "client #{inspect(pid)} exited: " <> Exception.format_exit(reason)
285+
message =
286+
"client #{Util.inspect_pid(pid)} exited: " <> Exception.format_exit(reason)
287+
279288
err = DBConnection.ConnectionError.exception(message)
280289

281290
{:keep_state, %{s | client: {ref, nil}},
@@ -290,14 +299,14 @@ defmodule DBConnection.Connection do
290299
)
291300
when is_reference(timer) do
292301
message =
293-
"client #{inspect(pid)} timed out because it checked out " <>
302+
"client #{Util.inspect_pid(pid)} timed out because it checked out " <>
294303
"the connection for longer than #{timeout}ms"
295304

296305
exc =
297306
case Process.info(pid, :current_stacktrace) do
298307
{:current_stacktrace, stacktrace} ->
299308
message <>
300-
"\n\n#{inspect(pid)} was at location:\n\n" <>
309+
"\n\n#{Util.inspect_pid(pid)} was at location:\n\n" <>
301310
Exception.format_stacktrace(stacktrace)
302311

303312
_ ->

lib/db_connection/connection_pool.ex

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ defmodule DBConnection.ConnectionPool do
1515

1616
use GenServer
1717
alias DBConnection.Holder
18+
alias DBConnection.Util
1819

1920
@behaviour DBConnection.Pool
2021

@@ -136,7 +137,7 @@ defmodule DBConnection.ConnectionPool do
136137
end
137138

138139
def handle_info({:"ETS-TRANSFER", holder, pid, queue}, {_, queue, _, _} = data) do
139-
message = "client #{inspect(pid)} exited"
140+
message = "client #{Util.inspect_pid(pid)} exited"
140141
err = DBConnection.ConnectionError.exception(message: message, severity: :info)
141142
Holder.handle_disconnect(holder, err)
142143
{:noreply, data}
@@ -175,14 +176,14 @@ defmodule DBConnection.ConnectionPool do
175176
# Check that timeout refers to current holder (and not previous)
176177
if Holder.handle_deadline(holder, deadline) do
177178
message =
178-
"client #{inspect(pid)} timed out because " <>
179+
"client #{Util.inspect_pid(pid)} timed out because " <>
179180
"it queued and checked out the connection for longer than #{len}ms"
180181

181182
exc =
182183
case Process.info(pid, :current_stacktrace) do
183184
{:current_stacktrace, stacktrace} ->
184185
message <>
185-
"\n\n#{inspect(pid)} was at location:\n\n" <>
186+
"\n\n#{Util.inspect_pid(pid)} was at location:\n\n" <>
186187
Exception.format_stacktrace(stacktrace)
187188

188189
_ ->

lib/db_connection/ownership/manager.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule DBConnection.Ownership.Manager do
33
use GenServer
44
require Logger
55
alias DBConnection.Ownership.Proxy
6+
alias DBConnection.Util
67

78
@timeout 5_000
89

@@ -394,7 +395,7 @@ defmodule DBConnection.Ownership.Manager do
394395

395396
defp not_found({pid, _} = from) do
396397
msg = """
397-
cannot find ownership process for #{inspect(pid)}.
398+
cannot find ownership process for #{Util.inspect_pid(pid)}.
398399
399400
When using ownership, you must manage connections in one
400401
of the four ways:

lib/db_connection/ownership/proxy.ex

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ defmodule DBConnection.Ownership.Proxy do
22
@moduledoc false
33

44
alias DBConnection.Holder
5+
alias DBConnection.Util
56
use GenServer, restart: :temporary
67

78
@time_unit 1000
@@ -21,6 +22,8 @@ defmodule DBConnection.Ownership.Proxy do
2122

2223
@impl true
2324
def init({caller, pool, pool_opts}) do
25+
Util.set_label("db_ownership_proxy")
26+
2427
pool_opts =
2528
pool_opts
2629
|> Keyword.put(:timeout, :infinity)
@@ -58,13 +61,13 @@ defmodule DBConnection.Ownership.Proxy do
5861

5962
@impl true
6063
def handle_info({:DOWN, ref, _, pid, _reason}, %{owner: {_, ref}} = state) do
61-
down("owner #{inspect(pid)} exited", state)
64+
down("owner #{Util.inspect_pid(pid)} exited", state)
6265
end
6366

6467
def handle_info({:timeout, deadline, {_ref, holder, pid, len}}, %{holder: holder} = state) do
6568
if Holder.handle_deadline(holder, deadline) do
6669
message =
67-
"client #{inspect(pid)} timed out because " <>
70+
"client #{Util.inspect_pid(pid)} timed out because " <>
6871
"it queued and checked out the connection for longer than #{len}ms"
6972

7073
down(message, state)
@@ -78,7 +81,7 @@ defmodule DBConnection.Ownership.Proxy do
7881
%{ownership_timer: timer} = state
7982
) do
8083
message =
81-
"owner #{inspect(pid)} timed out because " <>
84+
"owner #{Util.inspect_pid(pid)} timed out because " <>
8285
"it owned the connection for longer than #{timeout}ms (set via the :ownership_timeout option)"
8386

8487
# We don't invoke down because this is always a disconnect, even if there is no client.
@@ -150,7 +153,7 @@ defmodule DBConnection.Ownership.Proxy do
150153
end
151154

152155
def handle_info({:"ETS-TRANSFER", holder, pid, ref}, %{holder: holder, owner: {_, ref}} = state) do
153-
down("client #{inspect(pid)} exited", state)
156+
down("client #{Util.inspect_pid(pid)} exited", state)
154157
end
155158

156159
@impl true

lib/db_connection/task.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ defmodule DBConnection.Task do
1313
end
1414

1515
def init(fun, parent, opts) do
16+
DBConnection.Util.set_label("db_after_connect_task")
17+
1618
try do
1719
Process.link(parent)
1820
catch

lib/db_connection/util.ex

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
defmodule DBConnection.Util do
2+
@moduledoc false
3+
4+
@doc """
5+
Inspect a pid, including the process label if possible.
6+
"""
7+
def inspect_pid(pid) do
8+
with :undefined <- get_label(pid),
9+
:undefined <- get_name(pid) do
10+
inspect(pid)
11+
else
12+
label_or_name -> "#{inspect(pid)} (#{inspect(label_or_name)})"
13+
end
14+
end
15+
16+
defp get_name(pid) do
17+
try do
18+
Process.info(pid, :registered_name)
19+
rescue
20+
_ -> :undefined
21+
else
22+
{:registered_name, name} when is_atom(name) -> name
23+
_ -> :undefined
24+
end
25+
end
26+
27+
@doc """
28+
Set a process label if `Process.set_label/1` is available.
29+
"""
30+
def set_label(label) do
31+
if function_exported?(:proc_lib, :set_label, 1) do
32+
:proc_lib.set_label(label)
33+
else
34+
:ok
35+
end
36+
end
37+
38+
# Get a process label if `:proc_lib.get_label/1` is available.
39+
defp get_label(pid) do
40+
if function_exported?(:proc_lib, :get_label, 1) do
41+
# Avoid a compiler warning if the function isn't
42+
# defined in your version of Erlang/OTP
43+
apply(:proc_lib, :get_label, [pid])
44+
else
45+
# mimic return value of
46+
# `:proc_lib.get_label/1` when none is set.
47+
# Don't resort to using `Process.info(pid, :dictionary)`,
48+
# as this is not efficient.
49+
:undefined
50+
end
51+
end
52+
end

0 commit comments

Comments
 (0)