Skip to content

Commit

Permalink
Catch :noproc errors on cluster pools (#365)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrea Leopardi <an.leopardi@gmail.com>
  • Loading branch information
harunzengin and whatyouhide committed Apr 19, 2024
1 parent 820c34d commit 2a7dc8e
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 2 deletions.
18 changes: 16 additions & 2 deletions lib/xandra/cluster.ex
Expand Up @@ -433,7 +433,14 @@ defmodule Xandra.Cluster do
with_conn_and_retrying(
cluster,
options,
&Xandra.execute(&1, batch, options_without_retry_strategy)
fn conn ->
try do
Xandra.execute(conn, batch, options_without_retry_strategy)
catch
:exit, {:noproc, _} ->
{:error, ConnectionError.new("execute", {:cluster, :pool_closed})}
end
end
)
end

Expand All @@ -455,7 +462,14 @@ defmodule Xandra.Cluster do
with_conn_and_retrying(
cluster,
options,
&Xandra.execute(&1, query, params, options_without_retry_strategy)
fn conn ->
try do
Xandra.execute(conn, query, params, options_without_retry_strategy)
catch
:exit, {:noproc, _} ->
{:error, ConnectionError.new("execute", {:cluster, :pool_closed})}
end
end
)
end

Expand Down
7 changes: 7 additions & 0 deletions lib/xandra/connection_error.ex
Expand Up @@ -92,6 +92,13 @@ defmodule Xandra.ConnectionError do
"not connected to any of the nodes"
end

defp format_reason({:cluster, :pool_closed}) do
"""
the Xandra pool is closed, probably because the network connection dropped right after
Xandra.Cluster.Pool.checkout/0
"""
end

defp format_reason(reason) do
case :inet.format_error(reason) do
~c"unknown POSIX error" -> inspect(reason)
Expand Down
53 changes: 53 additions & 0 deletions test/integration/errors_test.exs
Expand Up @@ -2,6 +2,9 @@ defmodule ErrorsTest do
use XandraTest.IntegrationCase, async: true

alias Xandra.Error
alias Xandra.Cluster
alias Xandra.Cluster.Host
alias Xandra.ConnectionError

test "each possible error", %{conn: conn} do
assert {:error, reason} = Xandra.execute(conn, "")
Expand Down Expand Up @@ -45,4 +48,54 @@ defmodule ErrorsTest do
assert_raise Error, fn -> Xandra.prepare!(conn, "") end
assert_raise Error, fn -> Xandra.execute!(conn, "USE unknown") end
end

describe "on Xandra.Cluster level" do
defmodule Xandra.Cluster.PoolMock do
@behaviour :gen_statem

def child_spec(opts) do
%{
id: __MODULE__,
start: {__MODULE__, :start_link, [opts]},
type: :worker,
restart: :permanent
}
end

def start_link([]) do
:gen_statem.start_link(__MODULE__, :no_args, [])
end

def checkout(pid) do
:gen_statem.call(pid, :checkout)
end

@impl true
def init(:no_args) do
{dead_pid, ref} = spawn_monitor(fn -> :ok end)

receive do
{:DOWN, ^ref, _, _, _} -> :ok
end

{:ok, :waiting, [{dead_pid, %Host{}}]}
end

@impl true
def callback_mode do
:state_functions
end

def waiting({:call, from}, :checkout, data) do
{:keep_state_and_data, {:reply, from, {:ok, data}}}
end
end

test "noproc errors are caught" do
{:ok, cluster} = start_supervised(Xandra.Cluster.PoolMock)

assert {:error, %ConnectionError{action: "execute", reason: {:cluster, :pool_closed}}} =
Cluster.execute(cluster, "select * from system.peers")
end
end
end

0 comments on commit 2a7dc8e

Please sign in to comment.