在 elixir phoenix 应用程序中创建后台作业的正确方法

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

在这个控制器动作中,UserMailer.send_welcome_email是同步的,请求等待。

我想让它异步,所以生成了一个这样的进程

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

请求不会等到邮件已发送。

使用 spawn_link/1 启动进程将导致双向 link,因此无论是生成进程还是新生成的进程中最先死亡的进程都会杀死另一个进程(除非它正在捕获退出,这可能不应该)。这在某些情况下很好,而在其他情况下则不是那么好;例如,如果发送该电子邮件需要很长时间,Phoenix 请求可能会先完成,并冒着终止衍生进程的风险。

但是,由于 linking,进程孤立的风险不应该存在。

更好的方法肯定是创建一个 Supervisor(或使用 Task.Supervisor),并且您可以相当轻松地启动自己的后台作业设置。

但是,如果您想尝试一些不同的选择,可能值得查看您提到的 exqToniq 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 列表。

我相信您可以简单地使用 spawn 就可以完成工作,但这里的问题是,正如 Johan 所提到的,不会有任何重试或界面来追踪工作等等,所以您最好使用外部库。