Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Right way to create a background job in an elixir phoenix app

  def create(conn, %{"data" => %{"attributes" => user_params}}) do

    changeset = User.changeset(%User{}, user_params)

    case Repo.insert(changeset) do
      {:ok, user} ->
        UserMailer.send_welcome_email(user)
        conn
        |> put_status(:created)
        |> render("show.json", model: user)
      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> render(MyApp.ChangesetView, "error.json", changeset: changeset)
    end
  end

In this controller action, UserMailer.send_welcome_email is synchronous, and the request waits.

I wanted to make it asynchronous, so spawned a process like this instead

spawn_link(fn ->
  UserMailer.send_welcome_email(user)
end)

The request doesn't not wait until the mail has been sent.

  • Though it works, is it the right way to do ?
  • Are there any chances that these process become orphan or they just die after immediately executing?
  • Should we create a Supervisor instead?
  • Should we use a library like https://github.com/akira/exq instead? (I feel even if spawn_link fails, and logs it in our phoenix logs, it would do)
like image 269
Vysakh Sreenivasan Avatar asked Nov 30 '15 09:11

Vysakh Sreenivasan


1 Answers

Starting a process using spawn_link/1 will cause a bidirectional link, so whichever of the spawning process and the newly spawned process that happens to die first will kill the other one (unless it's trapping exits, which it probably shouldn't be). That's great in some cases, and not so great in others; if it takes a long time to send that e-mail, for example, the Phoenix request might finish first, and risk killing off the spawned process.

Due to the linking, however, there shouldn't be any risk of the processes getting orphaned.

A better approach is definitely to create a Supervisor (or using Task.Supervisor), and you could roll your own background job setup rather easily.

However, it might be worth looking at something like exq that you mentioned, or Toniq for example, that could possibly have everything you need already; especially things like retries in case of failure, and presistence. There are also some other interesting options in the Awesome Elixir list if you want to try out a few different alternatives.

like image 129
Johan Wärlander Avatar answered Nov 06 '22 22:11

Johan Wärlander