From 9058dfc8bfc234b8cb278ede25bf8f21db3ead30 Mon Sep 17 00:00:00 2001 From: Andrea Leopardi Date: Sun, 14 Apr 2024 17:42:32 +0200 Subject: [PATCH] Ensure socket owner always exits (#266) --- lib/redix/connection.ex | 8 ++++++-- lib/redix/socket_owner.ex | 13 +++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/redix/connection.ex b/lib/redix/connection.ex index c8f3f82..1172bc3 100644 --- a/lib/redix/connection.ex +++ b/lib/redix/connection.ex @@ -271,9 +271,13 @@ defmodule Redix.Connection do {:keep_state, data, actions} {:error, _reason} -> - # The socket owner will get a closed message at some point, so we just move to the - # disconnected state. + # The socket owner is not guaranteed to get a "closed" message, even if we close the + # socket here. So, we move to the disconnected state but also notify the owner that + # sending failed. If the owner already got the "closed" message, it exited so this + # message goes nowere, otherwise the socket owner will exit and notify the connection. + # See https://github.com/whatyouhide/redix/issues/265. :ok = data.transport.close(data.socket) + send(data.socket_owner, {:send_errored, self()}) {:next_state, :disconnected, data} end else diff --git a/lib/redix/socket_owner.ex b/lib/redix/socket_owner.ex index 700e936..4def577 100644 --- a/lib/redix/socket_owner.ex +++ b/lib/redix/socket_owner.ex @@ -50,6 +50,19 @@ defmodule Redix.SocketOwner do end end + # The connection is notifying the socket owner that sending failed. If the socket owner + # gets this, it can stop normally without waiting for the "closed"/"error" network + # message from the socket. + def handle_info({:send_errored, conn}, %__MODULE__{conn: conn} = state) do + error = + case state.transport do + :ssl -> {:ssl_error, :closed} + :gen_tcp -> {:tcp_error, :closed} + end + + stop(error, state) + end + def handle_info({transport, socket, data}, %__MODULE__{socket: socket} = state) when transport in [:tcp, :ssl] do :ok = setopts(state, socket, active: :once)