Tasks

  • Extends spawn to provide better error & introspection

  • Meant to execute on task with little communication, like turning seq code into async to compute values/send requests

Methods Overview

  • Task.start/1

  • Task.start_link/1

  • Task.async/1 - expects reply that is always sent (will crash if caller crashes)

  • Task.await/1

Sequential => Concurrent Code

task = Task.async(fn -> do_some_work() end)
res = do_some_other_work()
res + Task.await(task)

Adhoc Tasks

Can easily run without a supervisor for unessential tasks like emails

Task.start(fn -> send_email_to_user(user) end) # 🎉

Async requests

1..2 |> Task.async_stream(fn(_) -> DailyHelper.createDailyRoom() end) |> Enum.to_list()
#[{:ok, %{..}}, {:ok, %{..}}]

Task Supervisor

Summary:

Setup

Application.ex

    children = [
      {Task.Supervisor, name: YourApp.AccountSetupSupervisor}
    ]

Somewhere in app

{:ok, pid} = Task.Supervisor.start_child(ExampleApp.TaskSupervisor, fn -> background_work end)

account_setup.ex

Tasks will be run with when that ft

defmodule YourApp.AccountSetupSupervisor do
  def set_up_user_account(user) do
    opts = [restart: :transient]

    Task.Supervisor.start_child(__MODULE__, YourApp.CRM, :create_user, [user], opts)
    Task.Supervisor.start_child(__MODULE__, YourApp.Fulfillment, :set_nearest_location, [user], opts)
  end
end

Your CRM sample

defmodule YourApp.CRM do

  def create_user(user) do
    crm_data =
      user
      |> fetch_crm_data()
      |> parse()

    user
    |> YourApp.User.crm_changeset(crm_data)
    |> YourApp.Repo.update!()
  end

  defp fetch_crm_data(user) do
    # your code here
  end

  defp parse(data) do
    # you will probably want to parse results for use in a changeset
  end
end

Last updated