Task.start_link not calling given function

The function, run, given to Task.start_link is not run.

I am trying to write a CLI tool, using Bakeware, that takes a list of server names and runs a task on each one [it will ssh into each server and, hopefully, do something useful].

The task module contains the function, start_link, which, in turn, calls the other function, run. Each function prints to console.

defmodule ServerTask do
  use Task

  def start_link(args) do
    IO.inspect(args, label: "start_link")
    Task.start_link(__MODULE__, :run, args)
  end

  def run(args) do
    IO.inspect(args, label: "run")
  end

end

In my main module, I call the task module.

Supervisor.start_link([{ServerTask, [server, password]}], strategy: :one_for_one)

ServerTask.start_link prints out to console, but ServerTask.run doesn’t seem to be called.

Here is the complete code.

defmodule UpdateServer do
  use Bakeware.Script

  @impl Bakeware.Script
  def main(args) do

    password =
      Password.get("Password: ")
      |> String.replace_trailing("\n", "")

    case get_servers(args) do
      {:ok, servers} ->
        servers
        |> Enum.map(fn server -> update(server, password) end)

      {:error, error} ->
        IO.inspect(error, label: "MyError")
    end

    0
  end

  defp get_servers(arg_list) when is_list(arg_list) do
    with true <- Enum.all?(arg_list, fn item -> Enum.member?(servers(), item) end) do
      {:ok, arg_list}
    else
      _ -> {:error, "Server name not valid."}
    end
  end

  defp servers do
    [
      "server1",
      "server2",
      "server3",
      "server4"
    ]
  end

  defp update(server, password) do
    case Supervisor.start_link([{ServerTask, [server, password]}], strategy: :one_for_one) do
      {:ok, _pid} ->
        {:ok, pid}

      {:error, error} ->
        {:error, error}
    end
  end
end

defmodule ServerTask do
  use Task

  def start_link(args) do
    IO.inspect(args, label: "start_link")
    Task.start_link(__MODULE__, :run, args)
  end

  def run(args) do
    IO.inspect(:stdio, args, label: "run")
  end

end

Here:

Task.start_link(__MODULE__, :run, [args])

Whenever you see a MFA (module, function and arguments) the arguments is a list of given length. Otherwise, elixir cannot figure out the arity of the said function

1 Like

I made the change and it worked (i.e it printed out to console)! However, I tried again and it didn’t work.

I think the problem is that the main process exits before the task has completed. I put in a Process.sleep statement in the main function and now it works.