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

时间:2015-11-30 09:54:28

标签: 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

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

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

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

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

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

2 个答案:

答案 0 :(得分:10)

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

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

更好的方法绝对是创建Supervisor(或使用Task.Supervisor),您可以轻松地滚动自己的后台作业设置。

但是,您可能值得查看您提到的exqToniq等可能已经拥有的所有内容;尤其是在失败和重生的情况下重试的事情。如果您想尝试一些不同的替代方案,Awesome Elixir列表中还有一些其他有趣的选项。

答案 1 :(得分:0)

我相信你可以简单地使用spawn\3并且那就可以完成这项工作,但问题在于,正如Johan所提到的那样,不会有任何重试或界面来追踪工作,所以所以你最好不要使用外部库。