我最近将我的凤凰项目升级到了Ecto 2.0.2。我有一些代码使用Task.Supervisor.async_nolink
在自己的线程上对db进行一些更新。我的测试运行时出现以下错误(仅在我的测试中发生)
[error] Postgrex.Protocol (#PID<0.XXX.0>) disconnected: **
(DBConnection.ConnectionError) owner #PID<0.XXX.0> exited while
client #PID<0.XXX.0> is still running with: shutdown
现在我想想我理解发生了什么:在db事务完成之前,正在检查Ecto Sandbox连接池。根据文档(至少我阅读它们的方式),解决这些问题的方法是使用共享连接池:Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()})
我正在做的事情。不幸的是,这不起作用。
如何设置我的测试以便不会发生此错误?
答案 0 :(得分:6)
如果有其他人遇到这个问题,我会直接从语言作者Jose Valim那里得到答案:
是的,您对此问题的理解是正确的。这种情况正在发生,因为测试过程(拥有连接的人)已退出,但Task仍在使用其连接。使用{:shared,self()}无法修复它,因为测试仍然拥有连接,您只是隐式地共享它。
修复方法是在测试退出之前保证Task已完成。这可以通过调用Process.exit(task_pid,:kill)来完成。如果您不知道任务PID,可以调用Task.Supervisor.which_children(NameOfYourTaskSupervisor)来返回您随后遍历并终止它们的所有PID。但是,如果执行此方法,则测试无法同时运行(因为您可能会杀死另一个测试启动的任务)。
答案 1 :(得分:5)
我今天遇到了同样的问题,我想我已经找到了一个可能的解决方案,允许测试同时运行。
我使用此处描述的技术:http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/在运行测试时替换Task.Supervisor。
而不是:
private Product productTest;
private Category categoryTest;
private Supplier supplierTest;
@Before
public void setUp() throws Exception {
categoryTest = new Category("Test category", "", null);
supplierTest = new Supplier("Test supplier", null, null);
productTest = new Product("Test product","", 10, 20, 5, supplierTest, categoryTest);
categoryService.save(categoryTest);
supplierService.save(supplierTest);
productService.save(productTest);
}
@Test
public void findById() throws Exception {
Product retrieved = productService.findById(productTest.getId());
assertEquals(productTest, retrieved);
}
我正在做:
Task.Supervisor.async_nolink(TaskSupervisor, fn -> (...) end)
然后我定义@task_supervisor Application.get_env(:app, :task_supervisor) || Task.Supervisor
# ...
@task_supervisor.async_nolink(TaskSupervisor, fn -> (...) end)
TestTaskSupervisor
并在defmodule TestTaskSupervisor do
def async_nolink(_, fun), do: fun.()
end
中添加config :app, :task_supervisor, TestTaskSupervisor
。
这样,我确信任务将同步运行并在测试过程之前完成。
答案 2 :(得分:0)
此问题最终由Elixir v1.8.0和db_connection
v2.0.4解决。参见https://twitter.com/plataformatec/status/1091300824251285504和https://elixirforum.com/t/problem-asynchronizing-ecto-calls/19796/8
如果您使用的Elixir和DBConnection版本比上述版本更新,则测试应立即可用,没有任何错误。