<div dir="ltr">Hi Oliver,<div class="gmail_extra"><br><div class="gmail_quote">On 14 April 2016 at 23:23, Oliver Korpilla <span dir="ltr"><<a href="mailto:Oliver.Korpilla@gmx.de" target="_blank">Oliver.Korpilla@gmx.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Hello.<br>
<br>
I was trying to write a gen_server for handling a TCP connection. So, there would be an instance of gen_server for each open connection. (Each instance would have a copy of the socket returned by gen_tcp:listen to start accepting a connection from.)<br>
<br>
One thing I noticed is that gen_tcp does not seem to play very well with OTP's assumptions since accept is a blocking call, at least I understood it (and the principles) that way.<br>
<br>
So, on the net I saw examples dealing with accept in init/1. So, this will delay init/1 from finishing until there is either a timeout or there is a connection. I read somewhere else that it is a good practice to keep init from blocking...<br></blockquote><div><br></div><div>Yes, that is correct, because until your callback_module:init returns, your supervisor:init will not return which means your application startup hasn't finished, which in turn means it will block any applications after yours from starting.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
I saw an example (I think it was in "Learn You Some Erlang Good") that delayed the accept call by calling gen_server:cast and sending your own mailbox a trigger that was immediately followed by the blocking accept call. While this certainly was keeping init short, I wonder what was exactly gained here?<br>
<br>
Both init and handle_cast get executed in the new process started by gen_server:start_link. If either of them blocks, the process cannot react to anything else, right? So, how would a cast blocking the server be better than init? The process is still not responsive to events.<br></blockquote><div><br></div><div>init is executing in the context of the spawned gen_server process. It sends itself a message (which is non-blocking) and the init function returns, which means the supervisor:init function finishes executing, and your application startup is complete. Now your gen_server callback handle_cast is immediately called which then calls the gen_tcp:accept blocking call. It is okay for this to be blocked, because that is the main purpose of this process - block until a connection is available. The blocking nature is a problem only in two situations.</div><div><br></div><div>1. Code upgrade tends to be a problem. If you update the module invoking the blocking gen_tcp:accept twice, with no intervening socket connections being accepted, the server process will be killed, because your process hasn't handled the code upgrade message.</div><div><br></div><div>2. The gen_server process handles any other application specific messages - which as you've surmised will be blocked.</div><div><br></div><div>I typically use the following pattern for accepting TCP connections.</div><div><br></div><div><a href="https://gist.github.com/cmullaparthi/18ba2219befbf7a3c44c28cab004456f">https://gist.github.com/cmullaparthi/18ba2219befbf7a3c44c28cab004456f</a> </div><div><br></div><div>This frees up your process which owns the listen socket (tcp_server.erl) to handle other messages as well. The process which is blocking (tcp_socket.erl) is not doing anything useful until it gets a TCP connection.<br></div><div><br></div><div>I hope this helps.</div><div><br></div><div>cheers,</div><div>Chandru</div><div><br></div></div></div></div>