主管不会在 econnrefused 上重新启动(在 init/1 中抛出)
Posted
技术标签:
【中文标题】主管不会在 econnrefused 上重新启动(在 init/1 中抛出)【英文标题】:Supervisor does not restart on econnrefused (thrown in init/1) 【发布时间】:2017-11-11 06:49:30 【问题描述】:我有一个 gen_server 的 init
函数,我连接到 rabbitmq。当一切正常时,它工作得非常好,但是当连接到rabbitmq失败并且我调用exit
时,进程不会重新启动。
我想让主管在我调用exit
后重新启动这个过程。
从概念上讲,我的init
函数是这样的:
init(_Args) ->
process_flag(trap_exit, true),
case connect() of
error, econnrefused ->
timer:sleep(1000),
exit(econnrefused);
ok, Connection ->
.....
end,
ok, .
这是我的主管:
-module(tasks_manager_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
-define(SERVER, ?MODULE).
start_link() ->
supervisor:start_link(local, ?SERVER, ?MODULE, []).
init([]) ->
ok,
#strategy => one_for_one,
intensity => 50,
period => 10,
[#id => tasks_manager_serv_id,
start => tasks_manager_serv, start_link, [],
restart => permanent,
shutdown => brutal_kill,
type => worker,
modules => [tasks_manager_serv]].
我收到的错误如下。您可以看到此错误没有重新启动,它只是终止:
Starting global,tasks_da_serv (<0.479.0>)
Starting global,tasks_manager_serv (<0.483.0>)
=INFO REPORT==== 9-Jun-2017::09:52:46 ===
application: tasks
exited: shutdown,
failed_to_start_child,tasks_manager_sup_id,
shutdown,
failed_to_start_child,tasks_manager_serv_id,
econnrefused,
tasks_app,start,[normal,[]]
type: permanent
"Kernel pid terminated",application_controller,"application_start_failure,tasks,shutdown,failed_to_start_child,tasks_manager_sup_id,shutdown,failed_to_start_child,tasks_manager_serv_id,econnrefused,tasks_app,start,[normal,[]]"
Kernel pid terminated (application_controller) (application_start_failure,tasks,shutdown,failed_to_start_child,tasks_manager_sup_id,shutdown,failed_to_start_child,tasks_manager_serv_id,econnrefu
我也尝试过向self()
(来自init
函数)发送一条消息,并在handle_cast
中连接到rabbit,但效果不佳。
我仍在学习 Erlang/OTP,如果我问一些明显的问题,但我在文档中找不到任何问题的答案,请原谅我。
【问题讨论】:
我找不到这个文档,但看起来主管没有重新启动进程,因为它在init
中退出。如果我添加self() ! connect
然后退出handle_info(connect, ...)
,它会为我重新启动它。
@Dogbert,supervisor:start_link() docs? ---> 如果supervisor及其子进程创建成功(即所有子进程启动函数返回ok,Child, ok,Child,Info, 或者忽略),函数返回 ok,Pid,其中 Pid 是主管的 pid....如果 Module:init/1 失败或返回不正确的值,则此函数返回 error,Term,其中 Term 是包含有关错误信息的术语,并且主管因Term终止
换句话说,你必须能够让主管的孩子第一次启动——否则不会创建主管进程。
@7stud 不是在OP问题中开始的supervisor
,而是由它开始的gen_server
。
主管子启动确实必须成功,但没有什么可以阻止您设计init/1
尝试多次连接,然后最终放弃。如果主管启动其他希望rabbitmq 设施可用的孩子,那么这可能比允许它启动并异步尝试连接要好......但你真的需要重试吗?如果您在不重试的情况下进行连接,则整个应用程序会由于外部资源不可用而相对较快地失败,并且管理员很清楚可以处理它。
【参考方案1】:
感谢问题下方的 cmets,我能够解决它。
基本上问题是进程没有正确启动,因为exit(econnrefused)
在init/1
函数中。这就是主管没有重新启动进程的原因 - 它不会重新启动未能初始化的进程。
现在我正在向self()
发送一条消息,然后在hangle_info/2
中捕获它,如下所示:
init(_Args) ->
process_flag(trap_exit, true),
io:format("Starting ~p (~p)~n", [global, ?MODULE, self()]),
self() ! connect,
ok, .
handle_info(connect, State) ->
ok, Connection, Channel = establish_rabbit_connection(),
noreply, #stateconnection = Connection, channel = Channel;
【讨论】:
以上是关于主管不会在 econnrefused 上重新启动(在 init/1 中抛出)的主要内容,如果未能解决你的问题,请参考以下文章