0

我在我的 Phoenix 应用程序中有一个测试,它正在测试Phoenix.PubSub使用 Genserver 的订阅者。订阅者将一些数据库工作作为其handle_info/2.

test "sending creating a referral code upon user registration" do
  start_supervised(MyApp.Accounts.Subscriber)
  user = insert(:user)

  Phoenix.PubSub.broadcast(MappApp.PubSub, "accounts", {:register, user})

  assert_eventually(Repo.exists?(ReferralCode))

  stop_supervised(MyApp.Accounts.Subscriber)
end

单独运行这个测试模块就可以了。然而,当我运行我的整个测试套件时,我得到一个这样的错误(测试仍然通过):

[error] GenServer MyApp.Accounts.Subscriber terminating
** (stop) exited in: DBConnection.Holder.checkout(#PID<0.970.0>, [log: #Function<9.124843621/1 in Ecto.Adapters.SQL.with_log/3>, cache_statement: "ecto_insert_referral_codes", timeout: 15000, pool_size: 10, pool: DBConnection.Ownership])
    ** (EXIT) shutdown: "owner #PID<0.969.0> exited"
    <stacktrace...>

这看起来是一个问题,当进程终止时数据库连接仍然处于打开状态,因此它不会优雅地死掉。但我不确定如何处理这个问题。

有关如何防止此错误的任何建议?

4

1 回答 1

0

我今天遇到了这个。任何时候您在单独的子进程中执行数据库操作(例如,在 aGenStageGenServeret al 中触发的数据库操作),您都需要仔细阅读沙盒适配器文档。有一个专门处理此错误的常见问题解答,解决方案可以是显式授予沙盒适配器访问子进程的权限,如下所示(来自文档):

test "gets results from GenServer" do
  {:ok, pid} = MyAppServer.start_link()
  Ecto.Adapters.SQL.Sandbox.allow(Repo, self(), pid)
  assert MyAppServer.get_my_data_fast(timeout: 1000) == [...]
end

或者您可以通过更改测试setup来设置模式来启用“共享”Sandbox模式:

  setup do
    :ok = Sandbox.checkout(Repo)
    Sandbox.mode(Repo, {:shared, self()})
  end

后者我更幸运,但请注意,如果您在任何地方明确使用其他适配器(例如进行原始数据库调用),那么它可能会导致测试失败(因为它无法再获得连接)。

于 2020-11-25T19:08:57.080 回答