如何在没有测试警告的情况下从控制器运行"即发即弃"任务?



在我的凤凰应用程序中,我有一个像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

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

有没有办法更明确地"即发即弃"?例如,如果我可以从控制器调用Task.forget_about(task),那就太好了,但这并不存在。

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

直接来自文档

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

使用 Task.Supervisor.async_nolink/2

Task.Supervisor.async_nolink/2在这里做了我想要的:

启动可以等待的任务。

这意味着我可以在我愿意的测试中调用Task.await(task)

但是,这也意味着启动任务的过程"没有链接"。

这实际上很重要,测试失败告诉我这一点,尽管我没有意识到这一点。传入的请求由一个进程处理,该进程在发送响应后死亡。因此,如果后台作业链接到该进程,它也会死亡。

为此,我必须首先将其添加到我的监督树中:

supervisor(Task.Supervisor, [[name: MyApp.TaskSupervisor]])

name:只是一个原子;这并不意味着我必须有一个这个名字的模块。

然后我能够打电话:

Task.Supervisor.async_nolink(
MyApp.TaskSupervisor,
fn -> do_whatever end
)

相关内容

  • 没有找到相关文章

最新更新