I've got several tasks that I'm running asynchronously. Depending on the input, one or more might run long, but only one of the tasks will return the :success message.
slowtask = Task.async(slow())
fasttask = Task.async(fast())
How can I capture the first of the two tasks above to complete, without having to wait for the other? I've tried Task.find/2
, but because its implemented with enum, it seems to wait for all exit signals before finding a ref/message. My other thought was to poll this in Stream.cycle
, ignoring still alive tasks and catching one that has exited. It seems un elixir like to poll in this way though.
There is no easy way to do this on Elixir yet. Your best option is, if you are only waiting for those messages in a given process, is something like this:
defmodule TaskFinder do
def run do
task1 = Task.async fn -> :timer.sleep(1000); 1 end
task2 = Task.async fn -> :timer.sleep(5000); 2 end
await [task1, task2]
end
# Be careful, this will receive all messages sent
# to this process. It will return the first task
# reply and the list of tasks that came second.
def await(tasks) do
receive do
message ->
case Task.find(tasks, message) do
{reply, task} ->
{reply, List.delete(tasks, task)}
nil ->
await(tasks)
end
end
end
end
IO.inspect TaskFinder.run
Note you could also use this pattern to spawn tasks in a GenServer and use Task.find/2
to find the matching ones. I have also added this example to Elixir docs.