我该如何运行"开火并忘记"来自没有测试警告的控制器的任务?

时间:2017-08-09 14:03:23

标签: elixir phoenix-framework

在我的凤凰应用中,我有一个像Reviews.create(attributes)这样的模块功能。它会立即执行一些操作,并启动任务(使用Task.async)来执行其他工作。

我可以这样测试:

{:ok, new_review, task} = Reviews.create(attrs)
# verify that new_review is correct
Task.await(task)
# verify that the task did what it should

但是,我想要使用Reviews.create/1的主要地方来自控制器。从那里开始,我想把这个任务视为"开火,忘记"。这很简单:我只是不打电话给Task.await

这很好用,除了当我测试控制器时,我得到的错误如下:

[error] Postgrex.Protocol (#PID<0.344.0>) disconnected: ** 
(DBConnection.ConnectionError) owner #PID<0.753.0> exited
while client #PID<0.755.0> is still running with: shutdown

换句话说,它告诉我当控制器测试结束时,任务被杀死了。我不在乎的。

是否有某种方法可以更明确地做到这一点&#34;点燃并忘记&#34;?例如,如果从控制器我可以调用Task.forget_about(task),但这不会存在,那将是很好的。

2 个答案:

答案 0 :(得分:4)

您需要使用Task.start/1。它基本上以相同的方式运行,它只是在不同的进程中运行您的函数,但它不会以任何方式链接到生成它的进程。

直接来自文档

  

仅在将任务用于副作用时使用(即对返回的结果不感兴趣)并且不应将其链接到当前进程。

答案 1 :(得分:1)

使用Task.Supervisor.async_nolink / 2

Task.Supervisor.async_nolink/2做了我想要的事情:

  

启动可以等待的任务。

这意味着我可以在我关心的测试中调用supervisor(Task.Supervisor, [[name: MyApp.TaskSupervisor]])

然而,这也意味着没有链接&#34;到开始任务的过程。

这实际上非常重要,测试失败告诉了我,尽管我没有意识到这一点。传入请求由在响应发送后死亡的进程处理。因此,如果后台作业与该过程相关联,那么它也会死亡。

要做到这一点,我必须先将其添加到我的监督树中:

name:

Task.Supervisor.async_nolink( MyApp.TaskSupervisor, fn -> do_whatever end ) 只是一个原子;它并不意味着我必须有一个名称的模块。

然后我可以致电:

<input type="text" name="trxNumber-{{i}}" class="form-control" minlength="1" maxlength="20" [(ngModel)]="trxNumberList[index].trxNumber" />