如何测试由Elixir.Task实现的异步数据库事务?

时间:2019-07-12 05:42:22

标签: elixir ecto

我试图在Phoenix控制器中使用Elixir.Task在数据库中异步插入一条记录。 涵盖该控制器方法的测试,记录一个有关DB连接错误( DBConnection.OwnershipError )的异常。

我试图将控制器测试设置为异步,以便共享Ecto.Adapters.SQL.Sandbox模式。

链接到控制器任务的实现:link

链接到控制器的测试:link

日志:

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: []

1 个答案:

答案 0 :(得分:0)

您需要在测试中的使用字符串中添加标签

use UrlShortenerWeb.ConnCase, async: false

这将运行this line in test case,它将为所有进程提供对数据库连接的所有权,并且测试将同步运行。

另一种更复杂的方法-使用手动模式,并允许进程使用连接。
This post对所有权模式有很好的解释