在 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)
请求不会等到邮件已发送。
- 虽然有效,但这是正确的做法吗?
- 这些进程是否有可能成为孤儿进程或者它们在立即执行后就死掉了?
- 我们应该创建一个
Supervisor
吗?
- 我们应该改用 https://github.com/akira/exq 这样的库吗? (我觉得即使
spawn_link
失败,并将其记录在我们的 phoenix 日志中,它也可以)
使用 spawn_link/1
启动进程将导致双向 link,因此无论是生成进程还是新生成的进程中最先死亡的进程都会杀死另一个进程(除非它正在捕获退出,这可能不应该)。这在某些情况下很好,而在其他情况下则不是那么好;例如,如果发送该电子邮件需要很长时间,Phoenix 请求可能会先完成,并冒着终止衍生进程的风险。
但是,由于 linking,进程孤立的风险不应该存在。
更好的方法肯定是创建一个 Supervisor
(或使用 Task.Supervisor
),并且您可以相当轻松地启动自己的后台作业设置。
但是,如果您想尝试一些不同的选择,可能值得查看您提到的 exq
或 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 列表。
我相信您可以简单地使用 spawn
就可以完成工作,但这里的问题是,正如 Johan 所提到的,不会有任何重试或界面来追踪工作等等,所以您最好使用外部库。
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
失败,并将其记录在我们的 phoenix 日志中,它也可以)
使用 spawn_link/1
启动进程将导致双向 link,因此无论是生成进程还是新生成的进程中最先死亡的进程都会杀死另一个进程(除非它正在捕获退出,这可能不应该)。这在某些情况下很好,而在其他情况下则不是那么好;例如,如果发送该电子邮件需要很长时间,Phoenix 请求可能会先完成,并冒着终止衍生进程的风险。
但是,由于 linking,进程孤立的风险不应该存在。
更好的方法肯定是创建一个 Supervisor
(或使用 Task.Supervisor
),并且您可以相当轻松地启动自己的后台作业设置。
但是,如果您想尝试一些不同的选择,可能值得查看您提到的 exq
或 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 列表。
我相信您可以简单地使用 spawn
就可以完成工作,但这里的问题是,正如 Johan 所提到的,不会有任何重试或界面来追踪工作等等,所以您最好使用外部库。