我有一个创建Question
并将此问题插入数据库的系统,我点击了我设置的链接。这是凤凰城的简单话题。创建控制器操作为其设置链接,然后单击按钮以触发该操作。
这适用于现在。但下一阶段是让系统在没有任何UI干预的情况下创建问题。所以,这让我进入了Elixir / Phoenix的新地方。我的新问题是:我需要在x时刻自动运行此功能。
在Elixir / Phoenix中实施后台任务的最惯用方法是什么?我对Genserver或Supervisors知之甚少,但我想我已经准备好开始学习这些工具了。尽管如此,你将如何解决将逻辑转移到后台工作的问题。
def build_question(conn, _params) do
case Questions.create_total_points_question(conn) do
{:ok, _question} ->
conn
|> put_flash(:info, "Question created successfully.")
|> redirect(to: page_path(conn, :index))
{:error, _msg} ->
conn
|> redirect(to: page_path(conn, :index))
end
end
此控制器操作是从链接触发的。需要在后台调用此代码。感谢您的帮助。
答案 0 :(得分:1)
你几乎没有选择。
一个是在您的操作中简单运行Task.async
,但是将您执行操作的进程与您生成的进程相关联,因此任务崩溃将影响生成它并等待它的进程。顺便说一句,在你的特殊情况下,我不认为你在行动中想要这个,因为你在等待结果时没有任何工作要做,所以没有必要。
第二个选项,如果您不想等待结果,请使用Task.start_link
。这没关系,但是再次作为启动功能的名称,任务进程与您的相关联,因此这两个中的任何一个崩溃都会导致其他崩溃。
第三个选项,是使用Task.Supervisor
,只需打开您的应用程序ex文件(可能是一个在项目中有名称并且在lib文件夹中)并在children = [...
列表下方添加如下此
children = [
...
supervisor(Task.Supervisor,[], [name: MyApp.TaskSupervisor])
]
这将在您的应用中启动名称为MyApp.TaskSupervisor
的超级用户进程,您可以调用该进程并告知要运行的代码并对其进行监督。
现在,第三个选项可让您在应用程序中获得更多控制权,因为:
您可以在documentation
中找到有关此内容的更多信息答案 1 :(得分:0)
我遇到了完全相同的问题,所以我决定给出一个尽可能简单的具体答案。
def start(_type, _args) do
# List all child processes to be supervised
children = [
# ...
# add the following line
{Task.Supervisor, name: MyApp.TaskSupervisor}
]
# ...
添加动态主管。
请参阅文档 here。Task.Supervisor.start_child(MyApp.TaskSupervisor, fn ->
IO.puts "I am running in a task"
end)
:temporary
请注意,在这种情况下,您不必等待任务。这也意味着错误处理取决于您。您可以在执行代码时应用选项(请参阅上一个链接)。默认的 def build_question(conn, _params) do
Task.Supervisor.start_child(MyApp.TaskSupervisor, fn ->
MyApp.Questions.create_total_points_question(conn)
end)
conn
|> put_flash(:info, "Question is currently being processed.")
|> redirect(to: page_path(conn, :index))
end
不会在失败时重新启动任务,其优点是不会因重复失败而使其父级(应用程序)崩溃。
现在,假设您不关心问题构建的结果,那么您的具体问题。我会像这样在控制器中实现它:
{{1}}
如果你在乎结果,那么这不是办法。在这种情况下,我建议使用 liveview。它可以: