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
吗?spawn_link
失败,并将其记录在我们的凤凰日志中,它也会这样做)答案 0 :(得分:10)
使用spawn_link/1
启动一个进程将导致一个双向链接,因此无论哪个产生进程和刚出现的进程都会先杀死另一个进程(除非它会捕获退出,它可能不应该'是)。在某些情况下这很好,在其他情况下则不是那么好;例如,如果发送该电子邮件需要很长时间,那么Phoenix请求可能会先完成,并且可能会导致生成的进程被终止。
但是,由于链接,不应该有任何进程成为孤儿的风险。
更好的方法绝对是创建Supervisor
(或使用Task.Supervisor
),您可以轻松地滚动自己的后台作业设置。
但是,您可能值得查看您提到的exq
或Toniq等可能已经拥有的所有内容;尤其是在失败和重生的情况下重试的事情。如果您想尝试一些不同的替代方案,Awesome Elixir列表中还有一些其他有趣的选项。
答案 1 :(得分:0)
我相信你可以简单地使用spawn\3
并且那就可以完成这项工作,但问题在于,正如Johan所提到的那样,不会有任何重试或界面来追踪工作,所以所以你最好不要使用外部库。