I have a GenServer that creates a connection with a remote host every x seconds and I'm having a hard time catching network related errors (more specifically :enetunreach
and :ehostunreach
).
** (EXIT from #PID<0.327.0>) shell process exited with reason: :enetunreach
** (EXIT from #PID<0.327.0>) shell process exited with reason: :ehostunreach
The base code I'm working with looks basically like this:
try do
# Create Connection
catch
type, call ->
IO.inspect("Something happened while trying to connect.")
IO.inspect(type)
IO.inspect(call)
end
Have already tried both catch
and raise
but it always takes everything down with these errors.
The most important thing you should have figured out, would be how processes do live in the OTP actor model. The process cannot interfere the behaviour of another process, including, but not limited to catching exceptions thrown/raised there.
Consider the following contrived example, mimicking the issue you have.
defmodule M do
use GenServer
# @impl GenServer
# def init(:ok), do: {:ok, Process.flag(:trap_exit, true)}
# @impl GenServer
# def handle_info({:EXIT, _pid, reason}, state),
# do: {:noreply, IO.inspect("CAUGHT!")}
@impl GenServer
def handle_call(:test, _from, state),
do: {:reply, Process.exit(self(), :foo), state}
end
{:ok, pid} = GenServer.start_link M, :ok
GenServer.call(pid, :test)
Until you have the commented lines uncommented, you’ll get back somewhat like [error] GenServer #PID<0.132.0> terminating
. The only possibility you have to control (not to control, actually, to supervise only) the flow of another process, is by monitoring it.
That said, you need to monitor the process you start, set your process to trap exits and react accordingly to {:EXIT, _, _}
message received.
TL;DR try/1
would catch exceptions raised within the same process only.