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

Vys*_*san 10 elixir phoenix-framework

  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
Run Code Online (Sandbox Code Playgroud)

在此控制器操作中,UserMailer.send_welcome_email是同步的,请求等待.

我想让它异步,所以产生了这样的过程

spawn_link(fn ->
  UserMailer.send_welcome_email(user)
end)
Run Code Online (Sandbox Code Playgroud)

请求不会等到邮件发送完毕.

  • 虽然它有效但是它是正确的方法吗?
  • 这些过程是否有可能成为孤儿,或者他们只是在立即执行后死亡?
  • 我们应该创建一个Supervisor吗?
  • 我们应该使用像https://github.com/akira/exq这样的库吗?(我觉得即使spawn_link失败了,也记录在我们的凤凰日志中,它会这样做)

Joh*_*der 10

使用启动进程spawn_link/1将导致双向链接,因此产生进程和刚出现的进程中的任何一个将首先杀死另一个(除非它捕获退出,它可能不应该是).在某些情况下这很好,而在其他情况下则不是很好; 例如,如果发送该电子邮件需要很长时间,那么Phoenix请求可能会先完成,并且可能会导致生成的进程被终止.

但是,由于链接,不应该有任何进程成为孤儿的风险.

一个更好的方法肯定是创建一个Supervisor(或使用Task.Supervisor),你可以很容易地滚动你自己的后台作业设置.

但是,可能值得看一下exq你提到的东西,或者例如Toniq,它可能已经拥有你需要的一切; 尤其是在失败和重生的情况下重试的事情.如果你想尝试一些不同的选择,在Awesome Elixir列表中还有一些其他有趣的选项.