Elixir: `mix local.hex` hangs indefinately

Created on 5 Oct 2018  路  16Comments  路  Source: elixir-lang/elixir

Environment

  • Elixir & Erlang/OTP versions (elixir --version):
Erlang/OTP 21 [erts-10.1] [source] [64-bit] [smp:8:4] [ds:8:4:10] [async-threads:1] [hipe]

Elixir 1.8.0-dev (c483c9c) (compiled with Erlang/OTP 21)
  • Operating system:
~/elixir> lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.5 LTS
Release:        16.04
Codename:       xenial

Current behavior

Running mix local.hex hangs with no output. I've tracked down the hang to this line by binary-searching using of IO.puts and commenting out lines.

Commenting out the line :httpc.set_option(:ipfamily, :inet6fb4, :mix) makes the request succeed. I'm unable to find documentation on the :inet6fb4 option for set_option - actually I'm unable to find documentation for http:set_option at all. I see that there exists a function called httpc:set_options (note plural options vs option).

Expected behavior

Mix should not hang. Commenting out the above line fixes the hang.

Mix Bug

Most helpful comment

Root-cause is that ipv6 is misconfigured on the machine.

Adding the following to sysctl fixed it:

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

Possible solutions: Add a timeouts around calls to :httpc (or read_httpc) to indicate a misconfiguration to the user, and/or auto retry without ipv6/ipv4 fallback.

All 16 comments

Root-cause is that ipv6 is misconfigured on the machine.

Adding the following to sysctl fixed it:

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

Possible solutions: Add a timeouts around calls to :httpc (or read_httpc) to indicate a misconfiguration to the user, and/or auto retry without ipv6/ipv4 fallback.

Great find @dymk!

Unfortunately :httpc does not have a timeout for the set_options operation. But I think we can do this:

task = Task.async(fn -> :httpc.set_option(:ipfamily, :inet6fb4, :mix) end)
_ = Task.yield(task, 5000) || Task.shutdown(task, :brutal_kill)

Can you please give it a try? Let us know if you have any questions. Thank you!

:httpc.request now appears to be the point at which the hang happens. If I had to guess, under the hood, the .set_option call is blocking in the :mix process, so .request is also hanging.

@dymk maybe we should wrap everything in a task then? but then we should give it a higher timeout. maybe of 30s or even more. at this point i don't know if it will be useful :(

Or maybe we could keep the code as I suggest above but, if it times out, we could say: "Tried to set to IPV6 and it did not work" or something of sorts.

Based on #8281, I think the best option is likely to add a timeout around the whole command.

@josevalim I am interested in taking a shot at this if work on it hasn't already started.

I see that there aren't any unit tests for the public function (Mix.Utils.read_path\2) that calls this piece of code. Do you have any suggestions for how to write a test for this case?

Thanks

@mhanberg since it needs the network, it is a bit tricky to test it. We could maybe start a tiny httpd server that serves some files but I am not sure if this is desirable.

That's what I was thinking, I'll see what I can do, thanks!

Hm, I think I have something similar on my machine.

mix local.hex --force doesn鈥檛 work. It just hangs. I investigated a bit further and this:

> :inets.start
> :ssl.start
> :httpc.request 'https://elixir-lang.org'

which runs perfectly on my other machines hangs and doesn鈥檛 return anything on that machine.

elixir --info returns this:

Erlang/OTP 21 [erts-10.1] [source] [64-bit] [smp:13:13] [ds:13:13:10] [async-threads:1] [hipe]

Elixir 1.7.3 (compiled with Erlang/OTP 20)

Sadly :httpc.set_option(:ipfamily, :inet6fb4, :mix) doesn't help and it looks like ipv6 is working properly because ping6 and curl -6 are both returning correct output.

Downgrading to this makes it work again on that machine:

Erlang/OTP 20 [erts-9.3.3.3] [source] [64-bit] [smp:13:13] [ds:13:13:10] [async-threads:10] [hipe] [kernel-poll:false]

Elixir 1.6.6 (compiled with OTP 19)

I have checked and in OTP21 the :httpc.set_option(:ipfamily, :inet6fb4, :mix) is deprecated, so i will go ahead and remove it, but I still think we should wrap the whole read_path operation in a task and give the user a reasonable error message in cases of timeout. :)

@josevalim, i have similar problem. When do you intend to include this fix in stable version?

@DmitryKK it will be in the next release, coming in two months. :)

Closing in favor of #8394.

And now mix does not use IPv6 ? ;(

It seems that mix does not work without ipv4 anymore. The current flags disable/not enable the use of ipv6 sockets. Erlang 22.

Was this page helpful?
0 / 5 - 0 ratings