Run mix tasks asynchronously under a single mix task?

I am trying to run multiple long-running mix tasks asynchronously under a single parent mix task. I tried adding the child mix tasks as Tasks to a Supervisor, but this doesn’t seem to work and the mix task exits immediately.

defmodule Mix.Tasks.MyApp.Server do
  use Mix.Task

  def run(_args) do
    children = [
      {Task, fn -> Mix.shell.cmd "cd assets && npm run start" end},
      {Task, fn -> Mix.Task.run "phx.server" end}
    ]
    Supervisor.init(children, strategy: :one_for_one)
  end
end

Is there a good way to run long-running mix tasks asynchronously under a single parent mix task?

Spawning background threads won’t prevent the process from exiting - that will happen when the last statement in run exits - so what you need to do is wait for that to happen. You were on the right lines. I think simplest thing is just create some tasks and await them all:

tasks = [ 
  Task.async(fn -> Mix.Task.run "my task" end),
  Task.async(fn -> Mix.Task.run "my task2" end),
]
Enum.map(tasks, &Task.await/1)

I would think using Task.yield_many is a better option because all Task.await calls will sequentially wait for each task, one by one, while Task.yield_many does not mandate an order in which the tasks will be executed.

EDIT: full code is always easier to read:

[
  Task.async(fn -> Mix.Task.run "my task" end),
  Task.async(fn -> Mix.Task.run "my task2" end),
]
|> Task.yield_many

Thanks for the quick response!

This solution works perfectly except that the default timeout for Task.await/1 is 5 seconds, so I added the :infinity atom to keep the tasks running indefinitely.

tasks = [ 
  Task.async(fn -> Mix.Task.run "my task" end),
  Task.async(fn -> Mix.Task.run "my task2" end),
]
Enum.map(tasks, &Task.await(&1, :infinity))
2 Likes

All the tasks will start immediately, awaiting them in order is fine since he needs them all complete before he exits, it will take exactly as long as the slowest task. yield_many is for when you need timeouts and want to get the first results, like a server processing in a loop.