You should be running your tasks under a supervisor, so another approach would be something like this:
defmodule MyApp.SomeSupervisor do
def start_some_task(fun, args) do
Task.Supervisor.start_child(__MODULE__, ...)
end
# For tests: find all children spawned by this supervisor and wait until they finish.
def wait_for_completion() do
pids = Task.Supervisor.children(__MODULE__)
Enum.each(pids, &Process.monitor/1)
wait_for_pids(pids)
end
defp wait_for_pids([]), do: nil
defp wait_for_pids(pids) do
receive do
{:DOWN, _ref, :process, pid, _reason} -> wait_for_pids(List.delete(pids, pid))
end
end
end
In your test, call MyApp.SomeSupervisor.wait_for_completion()
. It’s not perfect, since it might needlessly wait for tasks not related to your particular tests, but it my case worked good enough.