Background
I have a GenServer process, that i need to kill if it tries to do an action and fails. I am able to kill the process, but it is not sending the correct message to it’s supervisor.
Code
Let’s assume I have the following code:
@impl GenServer
def handle_info({:critical_action}, state) do
case Logic.perform_action(state) do
{:ok, _res} -> {:noreply, Logic.update_state(state)}
:error -> Process.exit(self(), :critical_action_failed)
end
end
So, upon receiving a message, my GenServer process will attempt to execute it. Because this action is complex, it may fail and if it does so I want it to die and to notify its supervisor or whoever created it (the father process is trapping exits).
Problem
According to the documentation:
The following behaviour applies if
reason
is any term except:normal
or:kill
:(…)
2. Ifpid
is trapping exits, the exit signal is transformed into a message{:EXIT, from, reason}
and delivered to the message queue ofpid
.
So, I should expect a message of type {:EXIT, _, :critical_action_failed}
, as seen in the following test:
test "kills worker if critical operation fails" do
Process.flag :trap_exit, true
args = [1, 2, 3]
{:ok, _conn} = Worker.start_link(args)
assert_receive {:EXIT, _, :critical_action_failed}
Process.flag :trap_exit, false
end
This code should pass. Yet it fails because of what I am actually getting:
No message matching {:EXIT, _, :critical_action_failed} after 100ms.
Process mailbox:
{:EXIT, #PID<0.301.0>, {:bad_return_value, true}}
Question
What am I missing? Why am I not getting the expected message ?