2016-07-12 52 views
6

Ho recentemente aggiornato il mio progetto phoenix in Ecto 2.0.2. Ho del codice che sta usando Task.Supervisor.async_nolink per fare alcuni aggiornamenti al db sul proprio thread. Sto ottenendo il seguente errore quando il mio test eseguiti (si verifica solo nei miei test)Ecto 2.0 SQL Sandbox Errore nei test

[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 

Ora io penso ho capito che cosa sta accadendo: Il pool di connessioni Ecto Sandbox viene controllato di nuovo in prima che la transazione db è completa . Secondo i documenti (almeno il modo in cui li ho letti) il modo per aggirare quella roba è usare un pool di connessioni condivise: Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()}) che sto facendo. Sfortunatamente questo non funziona.

Come configurare i miei test in modo che questo errore non si verifichi?

risposta

3

Se qualcun altro incontra questo, ho ottenuto una risposta indietro su questo direttamente dalla lingua Autore José Valim:

Sì, la comprensione del problema è corretta. Sta accadendo perché il processo di test, colui che possiede la connessione, è uscito ma l'attività sta ancora utilizzando la sua connessione. Usando {: shared, self()} non lo aggiusta perché il test sta ancora possedendo la connessione, lo stai solo condividendo implicitamente.

Il modo di risolvere è garantire che l'attività sia terminata prima che il test termini. Questo può essere fatto chiamando Process.exit (task_pid,: kill). Se non si conosce il PID attività, è possibile chiamare Task.Supervisor.which_children (NameOfYourTaskSupervisor) per restituire tutti i PID che vengono quindi attraversati e eliminati. Tuttavia, se si esegue questo approccio, il test non può essere eseguito contemporaneamente (dato che è possibile eliminare le attività avviate da un altro test).

+1

TLDR: non c'è soluzione. – Noma4i

+0

Grazie per aver segnalato ciò che è stato trovato. Ho usato il feedback di Jose per risolvere il problema per me. Quindi, questa è la soluzione. –

3

Ho avuto lo stesso problema oggi e penso di aver trovato una possibile soluzione che consente di eseguire i test contemporaneamente.

Sto utilizzando la tecnica descritta qui: http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/ per sostituire Task.Supervisor durante l'esecuzione dei test.

Invece di:

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

che sto facendo:

@task_supervisor Application.get_env(:app, :task_supervisor) || Task.Supervisor 
# ... 
@task_supervisor.async_nolink(TaskSupervisor, fn -> (...) end) 

e poi definire TestTaskSupervisor

defmodule TestTaskSupervisor do 
    def async_nolink(_, fun), do: fun.() 
end 

e aggiungere config :app, :task_supervisor, TestTaskSupervisor in config/test.exs.

In questo modo, sono sicuro che l'attività verrà eseguita in modo sincrono e terminerà prima del processo di test.