Assert_raise in a linked process, without knowing the pid

Hello all, I am trying to test a linked process raising an error. I consulted this link Can't figure out how to assert error in linked process with ExUnit and it proved very helpful. However, the solution in that thread requires that the linked process’s pid be known. The code I’m testing does not provide a pid, unfortunately. Here is the source code (GenRetry.Task.async/2 is basically Task.async):

def read({time,{:read, key}}) do
    num_of_nodes = Nodes.all_nodes()
    |> queue_to_list()
    |> length()

    task = GenRetry.Task.async(
      fn -> 
        value =,Server,:read,[time, key]) 
        case value do
          {:badrpc, _reason} -> raise ReadNodesUnresponsive
          value -> value
      retries: @retries_per_read * num_of_nodes,
      delay: @delay_per_read / num_of_nodes,
      exp_base: 1

And here is the test

test "raises error if only node is unresponsive" do
      with_mock(RPC, call: fn _node,_module,_fun,_args -> 
        {:badrpc, :reason}
      end) do
        Process.flag :trap_exit, true
        pid = self()

        catch_exit do
{1,{:read, 1}})          

        assert_received({:EXIT, _, {%ReadNodesUnresponsive{message: _}, _}}) #uses _ instead of pid


I am trying to match against all possible pids to see if an error message is sent. However, I get this test failure:

21:44:37.620 [error] Task #PID<0.304.0> started from #PID<0.296.0> terminating
** (Exceptions.ReadNodesUnresponsive) All the nodes are unresponsive
() lib/nectar_api_web/services/communication_service.ex:58: anonymous fn/2 in
(gen_retry) lib/gen_retry/worker.ex:21: GenRetry.Worker.handle_cast/2
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Function: #Function<0.31575502/0 in GenRetry.Task.task_function/2>
Args: []

It seems like the error was never caught! Is there any way to listen to all messages that are sent and see if any of them is an error message? Thank you.

1 Like

Why do you need a separate process if your function is just gonna wait for it to finish every time?

1 Like

The separate process is spawned by GenRetry, which handles catching errors and restarting the process. It is required to get the behavior I want.

GenRetry.Task.async returns the same normal %Task{} struct as Elixir’s Task functions. Have you tried using its pid field?

task ={1,{:read, 1}})
# some lines later, use the task's pid.

I’d temporarily replace the assert_received with:

receive do
   msg  ->
   10_000 ->
     IO.puts("No message")

to see if there is any type of message in the test process mailbox.

1 Like