gpt4 book ai didi

elixir - 受监督的 GenServer 没有重新启动?

转载 作者:行者123 更新时间:2023-12-04 01:08:07 27 4
gpt4 key购买 nike

我缩小了问题的大小,因为它太大了。这是代码:

defmodule MayRaiseGenServer do
use GenServer

def start_link do
IO.puts "started MyServer, name is #{__MODULE__}"

GenServer.start_link(__MODULE__, [], name: __MODULE__)
end

def maybe_will_raise do
GenServer.call(__MODULE__, :maybe_will_raise)
end

def handle_call(:maybe_will_raise,_from, state) do
IO.puts "maybe_will_raise called!"
:random.seed(:erlang.now)
number = Enum.to_list(1..100) |> Enum.shuffle |> List.first
IO.puts "number is #{number}"
if rem(number,2) != 0 do
raise "#{number}"
end
{:reply, {"You got lucky"}, state}
end
end

defmodule MayRaiseSupervisor do
use Supervisor

def start_link([]) do
IO.puts "starting supervisor, name is #{__MODULE__}"
Supervisor.start_link(__MODULE__, [])
end

def init(arg) do
IO.puts "initted with arg: #{arg}"
children = [
worker(MayRaiseGenServer, [])
]

supervise(children, strategy: :one_for_one, restart: :transient, name: __MODULE__)
end
end

MayRaiseSupervisor.start_link([])
IO.inspect MayRaiseGenServer.maybe_will_raise
:timer.sleep(2000)
IO.puts "after sleep"

一开始,我只看到了一次启动GenServer的消息,但现在我又看到了。这是输出:
starting supervisor, name is Elixir.MayRaiseSupervisor
initted with arg:
started MyServer, name is Elixir.MayRaiseGenServer
maybe_will_raise called!
number is 14
started MyServer, name is Elixir.MayRaiseGenServer

11:32:28.807 [error] GenServer MayRaiseGenServer terminating
** (RuntimeError) 14
lib/mini.ex:20: MayRaiseGenServer.handle_call/3
(stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
(stdlib) gen_server.erl:647: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: :maybe_will_raise
State: []
** (exit) exited in: GenServer.call(MayRaiseGenServer, :maybe_will_raise, 5000)
** (EXIT) an exception was raised:
** (RuntimeError) 14
lib/mini.ex:20: MayRaiseGenServer.handle_call/3
(stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
(stdlib) gen_server.erl:647: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
(elixir) lib/gen_server.ex:604: GenServer.call/3
lib/mini.ex:45: (file)
(elixir) lib/code.ex:363: Code.require_file/2

从上面的输出中,我不太清楚会发生什么。根据IO上显示的消息,看起来GenServer已重新启动,但为什么再次抛出异常?此外,在此代码中:
MayRaiseSupervisor.start_link([])
IO.inspect MayRaiseGenServer.maybe_will_raise
:timer.sleep(2000)
IO.puts "after sleep"

如果方法调用 MayRaiseGenServer.maybe_will_raise确实会引发错误,看起来像后面的行,即 timer.sleepIO.puts不会再跑了。即使我更改代码以尝试处理异常,如下所示:
MayRaiseSupervisor.start_link([])
try do
IO.inspect MayRaiseGenServer.maybe_will_raise
rescue
RuntimeError -> IO.puts "there was an error"
end
:timer.sleep(2000)
IO.puts "after sleep"

我好像还达不到最后的 IO.puts (如果有错误)。有没有办法处理对 maybe_will_raise 的调用?这将允许我处理它引发错误并继续执行?我猜主管在重新启动时不会自动重试一段代码。

最佳答案

作为我的观点。

当在 GenServer.call(MayRaiseGenServer, :maybe_will_raise, 5000) 中使用退出信号引发异常时,您上面的输出会告诉您堆栈跟踪。和错误日志,因为 terminate/2被调用的原因 {%RuntimeError{message: ...}, [...] .

您可以定义 terminate/2回调查看:

def terminate(reason, _state) do
IO.inspect reason
end

Terminate/2

If reason is not :normal, :shutdown nor {:shutdown, term} an error is logged.



但是当在 GenServer 回调中引发异常时(除了 init/1 )它会调用 terminate/2告诉服务器即将退出(已发送退出信号)。

所以这一行之后的代码不会被执行:
try do
IO.inspect MayRaiseGenServer.maybe_will_raise
...

but shouldn't the IO.puts "started MyServer" output appear again?



并且当您的 GenServer 退出时。您的主管将启动一个新的,将主进程与您的 GenServer 进程链接起来(您的 MayRaiseGenServer.start_link 再次接到电话)

最后一件事是如果你想让代码继续执行。你可以捕获 退出信号像这样:
MayRaiseSupervisor.start_link([])
try do
IO.inspect MayRaiseGenServer.maybe_will_raise
catch
:exit, _ -> IO.puts "there was an error"
end
:timer.sleep(2000)
IO.puts "after sleep"

但我认为你应该考虑使用 raise在您的 GenServer 回调中。希望有所帮助!

关于elixir - 受监督的 GenServer 没有重新启动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39278862/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com