2016-07-12 46 views
6

我最近將phoenix項目升級到了Ecto 2.0.2。我有一些代碼是使用Task.Supervisor.async_nolink在自己的線程上對數據庫進行一些更新。我收到以下錯誤我的測試運行時(只發生在我的測試中)Ecto 2.0 SQL Sandbox測試錯誤

[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 

現在我我明白髮生了什麼:該外生沙盒連接池被重新簽入前分貝交易完成。根據文檔(至少是我閱讀它們的方式),解決這個問題的方法是使用共享連接池:Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()})我正在這樣做。不幸的是,這是行不通的。

如何設置我的測試以避免發生此錯誤?

回答

3

如果任何人遇到這種情形,我得到了一個答案這回直接從語言的作者何塞·Valim:

是,你對問題的理解是正確的。發生這種情況是因爲測試過程(即擁有連接的人)已退出,但該任務仍在使用其連接。使用{:shared,self()}並不能解決它,因爲測試仍然擁有連接,你只是隱式分享它。

修復方法是確保任務在測試退出前完成。這可以通過調用Process.exit(task_pid,:kill)來完成。如果您不知道任務PID,則可以調用Task.Supervisor.which_children(NameOfYourTaskSupervisor)來返回您隨後遍歷的所有PID並殺死它們。但是,如果採用這種方法,測試不能同時運行(因爲您可能會終止另一個測試啓動的任務)。

+1

TLDR:沒有解決方案。 – Noma4i

+0

感謝您報告發現的內容。我用Jose的反饋很好地解決了我的問題。所以,這就是解決方案。 –

3

我今天遇到了同樣的問題,我想我已經找到了一個允許測試同時運行的解決方案。

我正在使用此處描述的技術:http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/以在運行測試時替換Task.Supervisor。

相反的:

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/test.exs添加config :app, :task_supervisor, TestTaskSupervisor

這樣,我確信任務將同步運行並在測試過程完成之前完成。