Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection timeout takes 20min #269

Open
gleopoldo opened this issue Jun 28, 2021 · 3 comments
Open

Connection timeout takes 20min #269

gleopoldo opened this issue Jun 28, 2021 · 3 comments

Comments

@gleopoldo
Copy link

The problem

Hello guys. We faced a problem sending a message through gen_smtp_client while simulating networking issues and noticed that it can take 20min to return a timeout error. In a large scale sending environment, where thousands of emails are sent per second, this can hurt significantly the application performance.

Reading the source code, I found that the connect call uses one timeout configuration passed via option list, while the read_possible_multiline_reply function uses another timeout configuration, defined in this macro.

Is it possible to use the same configuration for all, or split the timeout configuration in two (if, for some reason, someone wants to use different timeout for message receivement)?

@seriyps
Copy link
Collaborator

seriyps commented Jun 28, 2021

Oh... I think it might make sense to either use the same timeout for both or to introduce read_timeout option. No reason to have it hardcoded.

@gleopoldo
Copy link
Author

gleopoldo commented Jun 29, 2021

Hello again!

I've been trying to do a workaround for this issue while it's not solved. The best approach so far I found to be using Task (in our case, we're using elixir, not erlang). This module is backed by OTP, and allows someone to timeout an async call after 5000ms (or any other time interval needed).

However, this timeout would be applied to the entire message delivery, not to each network interaction individually. The code would look something like this:

    task = Task.Supervisor.async_nolink(MySupervisor, function)

    case Task.yield(task, timeout) || Task.shutdown(task) do
      {:ok, response} ->
        response

      nil ->
        {:error, :timeout}

      error = _ ->
        {:error, error}
    end

Reading some posts about erlang and error handling, I guess that the socket would be closed once the process that opened the socket dies because all allocated memory for a process is released back to the VM after that. I believe that it would work similarly to this error handling setup.

WDYT? Any improvements or considerations?

@juhlig
Copy link
Contributor

juhlig commented Oct 7, 2021

RFC5321 Section 4.5.3.2 says timeouts MUST be per-command (instead of timing the entire session or transaction), and lists recommended minimum timeouts for each command. So, in the long run, gen_smtp should provide configurable per-command timeouts and use the recommended values as defaults.

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

No branches or pull requests

3 participants