1

在我的应用程序中,我有一个 GenServer。它备份在代理中重新启动所需的数据。我想测试我的 GenServer 是否正确备份和恢复,所以我想启动备份代理,然后重新启动 GenServer 并查看它是否有效(记住重新启动之前的配置)。

现在我已经start_supervised!在测试设置中配置并启动了 GenServer(使用 )。我需要以某种方式重新启动该 GenServer。

有什么好的方法吗?我应该完全不同吗?是否有不同的、正确的测试重启行为的方法?

4

1 回答 1

1

child_spec主管决定何时通过该子进程的 重新启动其监督下的进程。默认情况下,当您定义 GenServer 模块并use GenServer在模块上使用时,默认(重新启动值)将为:permanent,这意味着如果退出,则始终重新启动此进程。

鉴于此,向它发送一个退出信号就足够了Process.exit(your_gen_server_pid, :kill):kill将确保即使进程正在捕获退出它也会被杀死),然后主管应该再次启动该进程,然后您可以进行断言。

您需要一种方法来解决“新” genserver 进程,因为它将被杀死,重新启动时它pid不会与原来的相同,通常您通过在启动它时提供一个名称来做到这一点。

如果您的 genserver 将状态作为其一部分加载,init您不一定需要监督它来测试备份行为,您可以单独启动它,杀死它,然后重新启动它。

取决于您如何建立备份等,可能存在边缘情况,但通常这就足够了。

更新:

要解决进程退出和重新启动的问题,您可以编写 2 个辅助函数来专门处理该问题。

def ensure_exited(pid, timeout \\ 1_000) do
  true = Process.alive?(pid)
  ref = Process.monitor(pid)
  Process.exit(pid, :kill)
  receive do
     {:DOWN, ^ref, :process, ^pid, _reason} -> :ok
  after
    timeout -> :timeout
  end
end

您可以改为使用 aname和 doGenServer.whereis来检索 pid,但想法是一样的。

为了确保它还活着:

def is_back_up?(name, max \\ 200, tries \\ 0) when tries <= max do
    case GenServer.whereis(name) do
       nil ->
         Process.sleep(5)
         is_back_up?(name, max, tries + 1)
       pid -> true
    end
end

def is_back_up?(_, _, _), do: false

基本思想是这样的。不确定是否已经有一些帮手来做这种事情。

然后您只需使用它(您可以编写第三个助手,它采用实时 pid、名称,并在一个“步骤”中完成所有操作),或编写:

:ok = ensure_exited(pid)
true = is_back_up?(name)
于 2019-07-27T14:04:19.843 回答