在我的凤凰应用中,我有一个像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)
,但这不会存在,那将是很好的。
答案 0 :(得分:4)
您需要使用Task.start/1
。它基本上以相同的方式运行,它只是在不同的进程中运行您的函数,但它不会以任何方式链接到生成它的进程。
直接来自文档
仅在将任务用于副作用时使用(即对返回的结果不感兴趣)并且不应将其链接到当前进程。
答案 1 :(得分:1)
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" />