Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use SO_REUSEPORT with Phoenix

I am interested in a zero-downtime deployment system that does not use Elixir/Erlang hot upgrades (due to the complexity of data migrations while the code is running).

I have heard that I may be able to use the SO_REUSEPORT option when binding the server to the adapter, such that I can run two instances of the same application bound to the the same address and port. My intent is to deploy version 2 on the same server as a running version 1, start version 2, and then gracefully stop version 1, which should allow incoming connections to naturally begin connecting exclusively to version 2.

Regardless of whether this works exactly as I plan - my intent is to test this configuration knowing that it behaves differently on different OSes - I would like to know the specific steps necessary to configure Phoenix to do this, as this seems to be a lower-level configuration within :gen_tcp.

If, alternatively, there is a way to configure the OS or Erlang VM to make all connections with this option enabled by default, that would be even better.

like image 832
ringmaster Avatar asked Jan 27 '17 00:01

ringmaster


1 Answers

You should specify raw SO_REUSEPORT flag for a socket in the format {:raw, protocol, option_num, value_bin} gen_tcp option/raw and pass it to the underlying transport.

Please note, that flags are different for mac/linux. In your config.exs:

so_reuseport =
  case :os.type() do
    {:unix, :linux} -> {:raw, 1, 15, <<1::32-native>>}
    {:unix, :darwin} -> {:raw, 0xffff, 0x0200, <<1::32-native>>}
  end

config :yourapp, YourApp.Endpoint,
  http: [port: {:system, "PORT"}, transport_options: [socket_opts: [so_reuseport]]]

Tested on Phoenix 1.4.9, but I guess older versions should be ok too. Here are the corresponding docs for used options.

like image 105
r_black Avatar answered Nov 15 '22 18:11

r_black