如何测试 GenServer 重启行为?
How to test GenServer restart behaviour?
在我的应用程序中,我有一个 GenServer。它备份在代理中重新启动所需的数据。我想测试我的 GenServer 是否正确备份和恢复,所以我想启动备份代理,然后重新启动 GenServer 看看它是否有效(记住重新启动之前的配置)。
现在我已经在测试设置中配置并启动了 GenServer(使用 start_supervised!
)。我需要以某种方式重新启动该 GenServer。
有什么好的方法吗?我应该完全不同地做吗?是否有不同的、正确的方法来测试重启行为?
主管决定何时通过该子进程的 child_spec
在其监督下重新启动进程。默认情况下,当您定义 GenServer 模块并在模块上使用 use GenServer
时,默认值 (restart values) 将为 :permanent
,这意味着,如果它退出,则始终重新启动此进程。
鉴于此,向它发送一个退出信号就足够了,Process.exit(your_gen_server_pid, :kill)
(:kill
将确保即使进程陷入退出也会被杀死),并且主管然后应该重新开始这个过程,然后你就可以做你的断言了。
你需要一种方法来解决 "new" 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
您可以改为使用 name
并执行 GenServer.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,名称,并在一个 "step" 中完成),或者写:
:ok = ensure_exited(pid)
true = is_back_up?(name)
在我的应用程序中,我有一个 GenServer。它备份在代理中重新启动所需的数据。我想测试我的 GenServer 是否正确备份和恢复,所以我想启动备份代理,然后重新启动 GenServer 看看它是否有效(记住重新启动之前的配置)。
现在我已经在测试设置中配置并启动了 GenServer(使用 start_supervised!
)。我需要以某种方式重新启动该 GenServer。
有什么好的方法吗?我应该完全不同地做吗?是否有不同的、正确的方法来测试重启行为?
主管决定何时通过该子进程的 child_spec
在其监督下重新启动进程。默认情况下,当您定义 GenServer 模块并在模块上使用 use GenServer
时,默认值 (restart values) 将为 :permanent
,这意味着,如果它退出,则始终重新启动此进程。
鉴于此,向它发送一个退出信号就足够了,Process.exit(your_gen_server_pid, :kill)
(:kill
将确保即使进程陷入退出也会被杀死),并且主管然后应该重新开始这个过程,然后你就可以做你的断言了。
你需要一种方法来解决 "new" 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
您可以改为使用 name
并执行 GenServer.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,名称,并在一个 "step" 中完成),或者写:
:ok = ensure_exited(pid)
true = is_back_up?(name)