Как протестировать асинхронную транзакцию базы данных, реализованную Elixir.Task?

Я пытаюсь асинхронно вставить запись в базу данных, используя Elixir.Task в контроллере Phoenix. Тест, который охватывает этот метод контроллера, регистрирует исключение, связанное с ошибкой подключения к базе данных (DBConnection.OwnershipError).

Я попытался установить тест контроллера как асинхронный, чтобы режим Ecto.Adapters.SQL.Sandbox был общим.

Ссылка на реализацию задачи контроллера: ссылка

Ссылка на тест для контроллера: ссылка

Журнал:

05:28:21.325 [error] Task #PID<0.438.0> started from #PID<0.436.0> terminating
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.438.0>.

When using ownership, you must manage connections in one
of the four ways:

* By explicitly checking out a connection
* By explicitly allowing a spawned process
* By running the pool in shared mode
* By using :caller option with allowed process

The first two options require every new process to explicitly
check a connection out or be allowed by calling checkout or
allow respectively.

The third option requires a {:shared, pid} mode to be set.
If using shared mode in tests, make sure your tests are not
async.

The fourth option requires [caller: pid] to be used when
checking out a connection from the pool. The caller process
should already be allowed on a connection.

If you are reading this error, it means you have not done one
of the steps above or that the owner process has crashed.

See Ecto.Adapters.SQL.Sandbox docs for more information.
    (ecto_sql) lib/ecto/adapters/sql.ex:618: Ecto.Adapters.SQL.raise_sql_call_error/1
    (ecto) lib/ecto/repo/schema.ex:649: Ecto.Repo.Schema.apply/4
    (ecto) lib/ecto/repo/schema.ex:262: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: #Function<4.97600206/0 in UrlShortenerWeb.LinkController.redirect_url/2>
    Args: []
05:28:21.380 [error] Task #PID<0.435.0> started from #PID<0.433.0> terminating
** (stop) exited in: DBConnection.Holder.checkout(#PID<0.434.0>, [log: #Function<11.104730475/1 in Ecto.Adapters.SQL.with_log/3>, cache_statement: "ecto_insert_visits", timeout: 15000, pool_size: 10, pool: DBConnection.Ownership])
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
    (db_connection) lib/db_connection/holder.ex:71: DBConnection.Holder.checkout/2
    (db_connection) lib/db_connection.ex:1030: DBConnection.checkout/3
    (db_connection) lib/db_connection.ex:1340: DBConnection.run/6
    (db_connection) lib/db_connection.ex:540: DBConnection.parsed_prepare_execute/5
    (db_connection) lib/db_connection.ex:533: DBConnection.prepare_execute/4
    (postgrex) lib/postgrex.ex:196: Postgrex.query/4
    (ecto_sql) lib/ecto/adapters/sql.ex:658: Ecto.Adapters.SQL.struct/10
    (ecto) lib/ecto/repo/schema.ex:649: Ecto.Repo.Schema.apply/4
    (ecto) lib/ecto/repo/schema.ex:262: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: #Function<4.97600206/0 in UrlShortenerWeb.LinkController.redirect_url/2>
    Args: []
05:28:21.380 [error] Task #PID<0.441.0> started from #PID<0.439.0> terminating
** (stop) exited in: DBConnection.Holder.checkout(#PID<0.440.0>, [log: #Function<11.104730475/1 in Ecto.Adapters.SQL.with_log/3>, cache_statement: "ecto_insert_visits", timeout: 15000, pool_size: 10, pool: DBConnection.Ownership])
    ** (EXIT) shutdown: "owner #PID<0.439.0> exited"
    (db_connection) lib/db_connection/holder.ex:71: DBConnection.Holder.checkout/2
    (db_connection) lib/db_connection.ex:1030: DBConnection.checkout/3
    (db_connection) lib/db_connection.ex:1340: DBConnection.run/6
    (db_connection) lib/db_connection.ex:540: DBConnection.parsed_prepare_execute/5
    (db_connection) lib/db_connection.ex:533: DBConnection.prepare_execute/4
    (postgrex) lib/postgrex.ex:196: Postgrex.query/4
    (ecto_sql) lib/ecto/adapters/sql.ex:658: Ecto.Adapters.SQL.struct/10
    (ecto) lib/ecto/repo/schema.ex:649: Ecto.Repo.Schema.apply/4
    (ecto) lib/ecto/repo/schema.ex:262: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: #Function<4.97600206/0 in UrlShortenerWeb.LinkController.redirect_url/2>
    Args: []

person Hassan Gharehhasan Loo    schedule 12.07.2019    source источник


Ответы (1)


Вам нужно добавить тег в используемую строку в тесте

use UrlShortenerWeb.ConnCase, async: false

Это запустит эту строку в тестовом примере , который предоставит право собственности на соединение с базой данных для всех процессов, а также тест будет выполняться синхронно.

Другой, более сложный способ — использовать ручной режим и разрешить процессу использовать соединение.
В этом посте очень хорошее объяснение режимов владения

person apelsinka223    schedule 12.07.2019
comment
Установка тега Aync как ложного не исправила это. Я не хотел использовать ручной режим, так как статья также не рекомендует его. - person Hassan Gharehhasan Loo; 15.07.2019
comment
Ошибка с тегом такая же? - person apelsinka223; 15.07.2019
comment
Да, это то же самое. - person Hassan Gharehhasan Loo; 17.07.2019
comment
Возможно, задаче не хватает времени для завершения запроса, попробуйте добавить Process.sleep(1000) в тест. Лучший способ - отправить несколько сообщений из задачи и assert_receive их в тесте, чтобы убедиться, что задача завершена, но сон тоже в порядке. - person apelsinka223; 17.07.2019
comment
Вообще, я не думаю, что добавление сна в тесты - хорошая идея, это делает тесты длительными и непредсказуемыми. - person Hassan Gharehhasan Loo; 29.07.2019
comment
Что я сделал в этом случае, так это отделил задачу, внедрил ее на основе ENV и смоделировал ее в тестовой среде, чтобы не вставлять в базу данных. - person Hassan Gharehhasan Loo; 29.07.2019