Skip to content

Commit 92f6cbc

Browse files
authored
Refine acceptor behaviour on abnormal conditions (#103)
* Fix case where acceptors shut down forever after max_connections is hit * Don't exit the acceptor process when handling an econnaborted error
1 parent d899b49 commit 92f6cbc

File tree

4 files changed

+40
-2
lines changed

4 files changed

+40
-2
lines changed

lib/thousand_island/acceptor.ex

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,13 @@ defmodule ThousandIsland.Acceptor do
2828
else
2929
{:error, :too_many_connections} ->
3030
ThousandIsland.Telemetry.span_event(span, :spawn_error)
31+
accept(listener_socket, connection_sup_pid, server_config, span, count + 1)
3132

32-
{:error, reason} when reason in [:closed, :einval, :econnaborted] ->
33+
{:error, :econnaborted} ->
34+
ThousandIsland.Telemetry.span_event(span, :econnaborted)
35+
accept(listener_socket, connection_sup_pid, server_config, span, count + 1)
36+
37+
{:error, reason} when reason in [:closed, :einval] ->
3338
ThousandIsland.Telemetry.stop_span(span, %{connections: count})
3439

3540
{:error, reason} ->

lib/thousand_island/logger.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ defmodule ThousandIsland.Logger do
2121
"""
2222
@spec attach_logger(log_level()) :: :ok | {:error, :already_exists}
2323
def attach_logger(:error) do
24-
events = [[:thousand_island, :acceptor, :spawn_error]]
24+
events = [
25+
[:thousand_island, :acceptor, :spawn_error],
26+
[:thousand_island, :acceptor, :econnaborted]
27+
]
2528

2629
:telemetry.attach_many("#{__MODULE__}.error", events, &__MODULE__.log_error/4, nil)
2730
end

lib/thousand_island/telemetry.ex

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,21 @@ defmodule ThousandIsland.Telemetry do
9797
9898
* `telemetry_span_context`: A unique identifier for this span
9999
100+
* `[:thousand_island, :acceptor, :econnaborted]`
101+
102+
Thousand Island was unable to spawn a process to handle a connection since the remote end
103+
closed before we could accept it. This usually occurs when it takes too long for your server
104+
to start processing a connection; you may want to look at tuning OS-level TCP parameters or
105+
adding more server capacity.
106+
107+
This event contains the following measurements:
108+
109+
* `monotonic_time`: The time of this event, in `:native` units
110+
111+
This event contains the following metadata:
112+
113+
* `telemetry_span_context`: A unique identifier for this span
114+
100115
## `[:thousand_island, :connection, *]`
101116
102117
Represents Thousand Island handling a specific client request
@@ -281,6 +296,7 @@ defmodule ThousandIsland.Telemetry do
281296
@type event_name ::
282297
:ready
283298
| :spawn_error
299+
| :econnaborted
284300
| :recv_error
285301
| :send_error
286302
| :sendfile_error

test/thousand_island/server_test.exs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,20 @@ defmodule ThousandIsland.ServerTest do
134134
assert :gen_tcp.recv(client, 0) == {:ok, ~c"HELLO"}
135135
assert :gen_tcp.recv(other_client, 0) == {:error, :closed}
136136
:gen_tcp.close(other_client)
137+
138+
# Close the first connection and ensure new connections are now accepted
139+
:gen_tcp.close(client)
140+
141+
# Give things enough time for the first connection to time out
142+
Process.sleep(500)
143+
144+
{:ok, third_client} = :gen_tcp.connect(:localhost, port, active: false)
145+
:ok = :gen_tcp.send(third_client, "BUONGIORNO")
146+
147+
# Give things enough time to send if they were going to
148+
Process.sleep(100)
149+
150+
assert :gen_tcp.recv(third_client, 0) == {:ok, ~c"BUONGIORNO"}
137151
end
138152

139153
test "should emit telemetry events as expected" do

0 commit comments

Comments
 (0)