📎 Webclip
Handling TCP connections in Elixir
The article explains a pattern for handling TCP connections in Elixir by keeping the socket inside a GenServer and using it as the single interface to the server. It starts with a simple Redis client example, then shows why blocking on :gen_tcp.recv/2 becomes a problem when multiple processes use the same GenServer.
Reading notes#
- TCP connections in Erlang and Elixir are handled with
:gen_tcp, and the article focuses on clients that connect to an external TCP server. - A GenServer is used to keep the TCP socket in its state and reuse it for all communication.
- The first version connects in
init/1, uses:binary, and setsactive: falseso messages are not delivered automatically. - Sending a command with
:gen_tcp.send/2and then reading with:gen_tcp.recv/2works, but it blocks the GenServer while waiting for a response. - To avoid blocking,
handle_call/3can return{:noreply, state}and later reply withGenServer.reply/2. - The article switches to
active: trueso TCP messages arrive as Erlang messages inhandle_info/2. - Because Redis replies sequentially, the GenServer keeps a queue of waiting clients and matches each response to the next client in line.
active: :onceis presented as a safer option thanactive: truebecause it delivers one TCP message at a time and reduces mailbox flooding.- The socket is reactivated with
:inet.setopts/2after a{:tcp, ...}message is handled. - The same pattern is described as common in database drivers and similar libraries, with examples such as eredis, postgrex, and mongodb.
- The article then introduces the
Connectionbehaviour to improve startup handling and reconnection support. - With
Connection,init/1can return{:connect, info, state}sostart_link/0returns quickly while the connection is established in the background. connect/2can return{:backoff, timeout, state}when:gen_tcp.connect/3fails, allowing retries after a delay.- The article ends by noting that the GenServer can be used with poolboy to form a pool of workers that checkout, use, and check in Redis clients.
