【问题标题】:Stop a GenServer after each test每次测试后停止 GenServer
【发布时间】:2021-04-14 05:17:34
【问题描述】:

背景

我有一组测试需要先启动 GenServer。根据经验,我知道在每次测试后进行清理是一个好习惯,所以我也想在每次测试后停止 GenServer。

问题

这里的问题是我不知道如何在测试完成后停止 GenServer。我总是遇到一些并发问题。

defmodule MyModuleTest do
  use ExUnit.Case

  alias MyModule

  setup do
    MyModule.Server.start_link(nil)
    context_info = 1
    more_info = 2
    %{context_info: context_info, more_info: more_info}
  end

  describe "some tests" do
    test "returns {:ok, order_id} if order was deleted correctly", context do
      # do test here that uses created server  and passed context
      assert actual == expected

      #clean up?
    end
  end
end

现在,我尝试了on_exit/2,如下所示:

  setup do
    {:ok, server} = MyModule.Server.start_link(nil)
    context_info = 1
    more_info = 2
    
    on_exit(fn -> GenServer.stop(server) end)

    %{context_info: context_info, more_info: more_info}   
  end

但我得到这个错误:

** (exit) exited in: GenServer.stop(#PID<0.296.0>, :normal, :infinity)
         ** (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

我觉得这退出得太早了。

我也尝试过使用start_supervised,但是由于我的GenServerhandle_continue 中的初始化时间很长,因此测试在服务器准备好之前运行。

问题

我该如何解决这个问题?

【问题讨论】:

    标签: elixir gen-server ex-unit


    【解决方案1】:

    我终于搞清楚是怎么回事了。

    原来start_supervised 正在按预期工作,实际上是等待 GenServer 结束 handle_continue(嗯,它不是完全等待,它仍然发送消息并将这些消息放入队列中等待适当的时间执行)。

    这里的问题是我没有完全清理我在handle_continue 中发起的所有内容。原来我启动的一些连接和进程即使在原始 GenServer 死后仍然存在。

    解决方案有两个方面:

    • 捕捉所有停止信号
    • 一旦检测到停止信号,执行正常关机

    在代码中,这被翻译成:

    def init(_) do
        Process.flag(:trap_exit, true) # trap all exits!
        {:ok, %{}, {:continue, :setup_queue}}
    end
    
    def handle_continue(:setup_queue, state) do
       # do heavy lifting
        {:noreply, state}
    end
    
    def terminate(_reason, state), do:
        # undo heavy lifting
    

    有了这个和start_supervised 在我的setup 块中,一切正常。

    【讨论】:

    • 有趣!哪些连接和进程在 GenServer 死亡后幸存下来?
    • 就我而言,我使用的是一个名为 :jobs, github.com/uwiger/jobs 的库。创建队列的进程死亡后,创建的队列不会被删除。所以我不得不手动完成。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 2017-06-05
    • 2020-03-25
    • 2018-12-17
    • 2015-03-26
    • 1970-01-01
    相关资源
    最近更新 更多