3

I'm failing to see how adding a supervisor to a crashing gen_tcp:listen-thread would actually restart that worker. Since crashing would render the port I wanna listen on useless for a brief moment. When a crash occur and I'm trying to manually restart my application I receive "{error,eaddrinuse}". I haven't implemented any supervisor for this worker yet since I fail to see how it would work.

How do I restart a gen_tcp:listen?

  • It sometimes seems like even the if the socket has been closed the port is still in use for a while. Don't know why. – rvirding May 21 '14 at 20:11
  • @rvirding - Apparently in cases where there were pending connections on the socket. If there are no pending connections, it should progress immediately to the CLOSED state. Alexander - Please see Paul's answer regarding the use of reuseaddr, which *should* be used for your server even if my answer helped. – Soup d'Campbells May 21 '14 at 20:36

2 Answers2

2

In most cases, as the listen socket is linked to the controlling process (the process that created it), a termination of this process will close the socket nicely and allow you to listen again on the same port.

For all other cases, you should pass {reuseaddr, true} option to gen_tcp:listen/2. Indeed, the listen socket of your application remains active for a brief moment after a crash, and this option allows you to reuse the address during this period.

Paul Guyot
  • 6,257
  • 1
  • 20
  • 31
  • reuseaddr is intended for a different purpose than the one you're suggesting. It may indeed work for that purpose, but it could also have nasty side-effects if used incorrectly. – Soup d'Campbells May 21 '14 at 15:01
  • reuseaddr is exactly what is blocking OP, and is required for uncatchable crashes. ranch uses this option as well. – Paul Guyot May 21 '14 at 15:13
  • The purpose of reuseaddr is to allow servers to re-use ports which have already been used, yes, but there are better ways to solve this particular issue, namely proper clean-up of the listening socket on termination, which ranch *also* does. A better use of reuseaddr is for high-volume servers managing many thousands of short-lived clients. – Soup d'Campbells May 21 '14 at 15:22
  • Actually, I believe proper cleanup occurs in most cases, without trapping exits, and OP really needs reuseaddr. I do not believe ranch traps exits to do proper cleanup of listen sockets. – Paul Guyot May 21 '14 at 15:47
  • Right you are that ranch doesn't use it (double-checked source). That being said, proper-cleanup *does* prevent the "already in use" problem as long as there are no pending connections, and as such *will* help him in this case. On my part, I was conflating the reuseaddr option with the system-level TCP option of the same name, which *globally* allows reuse of TIME_WAIT-ing ports and can create issues. As an option for listening it is widely used to reestablish a listening server which closed the socket abnormally (e.g., crashed). – Soup d'Campbells May 21 '14 at 20:33
1

Is the process managing the gen_tcp socket a gen_server? If so, it will make your life easier.

If it is a gen_server, add process_flag(trap_exit, true) to your init function. This makes it so that when your process "crashes", it calls the terminate/2 callback function prior to actually exiting the process. Using this method, you can manually close your listening socket in the terminate function, thereby avoiding the irritating port cleanup delay.

If you are not using a gen_server, the same principle still applies, but you must be much more explicit about catching your errors.

Soup d'Campbells
  • 2,333
  • 15
  • 14
  • Alternatively, you could also start the listening socket in a separate process from your "acceptor". Said process should do *nothing* beyond acting as a store for the socket, thereby ensuring it will never crash. This works because `gen_tcp:accept` can be called simultaneously from multiple processes. – Soup d'Campbells May 21 '14 at 14:39
  • Thank you for the fast reply! I'll try to add a trap since I'm running a gen_server (should have mentioned that). Regarding splitting the accept/listen - will that actually suffice if my application crashes? – Alexander Hades May 21 '14 at 14:52
  • If the entire application crashes then you would have the same issue even if you split the responsibility out. However, you would still benefit somewhat by virtue of only specifying trap_exit where you really need it and allowing your client processes to crash normally when it would be appropriate. Also, do take a look at ranch (https://github.com/extend/ranch) which can take care of a lot of this stuff for you. – Soup d'Campbells May 21 '14 at 14:59