Skip to content

Close sockets in case of unsuccessful connection#72

Open
FlorianGerhardt wants to merge 2 commits intosmartrent:mainfrom
FlorianGerhardt:fix_stale_sockets
Open

Close sockets in case of unsuccessful connection#72
FlorianGerhardt wants to merge 2 commits intosmartrent:mainfrom
FlorianGerhardt:fix_stale_sockets

Conversation

@FlorianGerhardt
Copy link
Copy Markdown

@FlorianGerhardt FlorianGerhardt commented Mar 14, 2026

Fixes #52
I had another device in the field with a firewall blocking the mqtt connection. Again, as in the issue, the device became unresponsive after some time. I noticed the same issue of file descriptors piling up and dug a bit deeper. It seems like the sockets are not getting closed if the connection times out. This fixes the issue.

The problem does not appear with no internet connection as the socket does not get created in that case.

Basically I checked with File.ls!("/proc/APP_PID/fd") |> Enum.count how many file descriptors are in use. The count increased everytime it tried connecting and timed out. The count went back to normal after stopping Tortoise311 Supervisor as the processes are linked.

Looking forward to feedback!

Copilot AI review requested due to automatic review settings March 14, 2026 01:54
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses issue #52 by preventing socket/file-descriptor leaks during repeated MQTT reconnect attempts when a connection attempt fails after the socket has been opened (e.g., timeouts or refused CONNACK).

Changes:

  • Refactors do_connect/2 to explicitly close the socket on unsuccessful post-connect outcomes (refused CONNACK, timeouts, and other errors).
  • Normalizes a post-connect timeout into {:error, :connection_timeout} after closing the socket.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/tortoise311/connection.ex
Comment on lines 687 to +697
%Connack{status: {:refused, _reason}} = connack ->
:ok = transport.close(socket)
connack

{:error, :timeout} ->
:ok = transport.close(socket)
{:error, :connection_timeout}

{:error, _reason} = error ->
:ok = transport.close(socket)
error
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Florian Gerhardt <florian.gerhardt92@gmail.com>
Copilot AI review requested due to automatic review settings March 14, 2026 02:12
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a socket/file-descriptor leak in Tortoise311.Connection by ensuring sockets are explicitly closed when a connection attempt fails after the socket has been created (e.g., timeouts while waiting for CONNACK).

Changes:

  • Refactors do_connect/2 to keep the created socket in scope for subsequent failure handling.
  • Closes the socket on CONNACK refusal and on send/recv errors (including :timeout and :closed).
  • Normalizes certain failure returns to higher-level connection errors (e.g., {:error, :connection_timeout}).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +691 to +701
{:error, :timeout} ->
:ok = transport.close(socket)
{:error, :connection_timeout}

{:error, :closed} ->
:ok = transport.close(socket)
{:error, :server_closed_connection}

{:error, _reason} = error ->
:ok = transport.close(socket)
error
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reconnection reaching max file descriptor limit

2 participants