我怎么知道什么时候是我的进程的最后一个周期由 erlang 中的主管重新启动
How can I know when it's the last cycle of my process restarted by the supervisor in erlang
我有一个 simple_one_for_one
主管 gen_fsm
children。
我希望每个 gen_fsm
child 仅在最后一次终止时发送消息。
有什么方法可以知道最后一个周期是什么时候?
这是我的主管:
-module(data_sup).
-behaviour(supervisor).
%% API
-export([start_link/0,create_bot/3]).
%% Supervisor callbacks
-export([init/1]).
%%-compile(export_all).
%%%===================================================================
%%% API functions
%%%===================================================================
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
RestartStrategy = {simple_one_for_one, 0, 1},
ChildSpec = {cs_fsm, {cs_fsm, start_link, []},
permanent, 2000, worker, [cs_fsm]},
Children = [ChildSpec],
{ok, {RestartStrategy, Children}}.
create_bot(BotId, CNPJ,Pid) ->
supervisor:start_child(?MODULE, [BotId, CNPJ, Pid]).
Pid
是启动监管者并发出命令启动 children 的进程的 Pid。
-module(cs_fsm).
-behaviour(gen_fsm).
-compile(export_all).
-define(SERVER, ?MODULE).
-define(TIMEOUT, 5000).
-record(params, {botId, cnpj, executionId, pid}).
%%%===================================================================
%%% API
%%%===================================================================
start_link(BotId, CNPJ, Pid) ->
io:format("start_link...~n"),
Params = #params{botId = BotId, cnpj = CNPJ, pid = Pid},
gen_fsm:start_link(?MODULE, Params, []).
%%%===================================================================
%%% gen_fsm callbacks
%%%===================================================================
init(Params) ->
io:format("initializing~n"),
process_flag(trap_exit, true),
{ok, requesting_execution, Params, 0}.
requesting_execution(timeout,Params) ->
io:format("erqusting execution"),
{next_state, finished, Params,?TIMEOUT}.
finished(timeout, Params) ->
io:format("finished :)~n"),
{stop, normal, Params}.
terminate(shutdown, _StateName, Params) ->
Params#params.pid ! {terminated, self(),Params},
ok;
terminate(_Reason, _StateName, Params) ->
ok.
我的观点是,如果进程在任何状态下失败,它应该仅在它最后一次被监督者重新启动时才发送消息(根据其重新启动策略)。
如果 gen_fsm
失败,它是否从具有相同状态数据的相同状态重新启动?如果不是,我怎样才能让它发生?
您可以将消息发送到 Module:terminate/3
函数,该函数在 StateName
函数之一 returns {stop,Reason,NewStateData}
时调用,以指示 gen_fsm
应该停止。
gen_fsm
是一个有限状态机,因此您可以决定它如何在状态之间转换。触发最后一个循环的东西也可能在传递给 Module:StateName/3
的 StateData
中设置一些东西,以便处理状态的函数知道它是最后一个循环。除非您提供一些我们可以分析和评论的代码,否则很难给出更具体的答案。
进一步澄清后编辑:
Supervisor 不会通知它的 children 它是什么时候重启它们的,它也不会通知 child 这是最后一次重启。后来这仅仅是因为它不知道这将是最后一次,直到主管进程实际上再次崩溃,而主管进程不可能预测到这一点。只有在 child crashed supervisor 之后才能计算 child 在一段时间内崩溃了多少次,以及是否允许再次重启 child 或者那是最后一次重启并且现在也是监督者去死的时候了
然而,没有什么能阻止 child 注册,例如在 ETS table 中,它重新启动了多少次。但它当然无助于扣除最后一次重启。
编辑 2:
当主管重新启动 child 时,它会使用标准 init
函数从头开始。 child 在崩溃之前的任何先前状态都将丢失。
请注意,崩溃是一种特殊情况,并不总是能够恢复状态,因为崩溃可能已经破坏了状态。与其尝试恢复状态或在完成重启 child 后询问主管,为什么不首先防止崩溃发生呢?您有两个选择:
I. 使用try/catch to catch any exceptional situations and act accordingly. It's possible to catch any error that would otherwise crash the process and cause supervisor to restart it. You can add try/catch
to any entry function inside the gen_fsm
process so that any error condition is caught before it crashes the server. See example function 1 or example function 2:
read() ->
try
try_home() orelse try_path(?MAIN_CFG) orelse
begin io:format("Some Error", []) end
catch
throw:Term -> {error, Term}
end.
try_read(Path) ->
try
file:consult(Path)
catch
error:Error -> {error, Error}
end.
II. 生成一个新进程来处理作业并在进程死亡时捕获 EXIT
信号。这允许 gen_fsm
异步处理作业并以自定义方式处理任何错误(不必像主管那样重新启动流程)。此部分标题为 Error Handling explains how to trap exit
signals from child processes. And this is an example of trapping signals,在 gen_server
中。检查 handle_info
函数,其中包含一些子句以捕获来自 children 进程的不同类型的 EXIT
消息。
init([Cfg, Id, Mode]) ->
process_flag(trap_exit, true),
(...)
handle_info({'EXIT', _Pid, normal}, State) ->
{noreply, State};
handle_info({'EXIT', _Pid, noproc}, State) ->
{noreply, State};
handle_info({'EXIT', Pid, Reason}, State) ->
log_exit(Pid, Reason),
check_done(error, Pid, State);
handle_info(_, State) ->
{noreply, State}.
我有一个 simple_one_for_one
主管 gen_fsm
children。
我希望每个 gen_fsm
child 仅在最后一次终止时发送消息。
有什么方法可以知道最后一个周期是什么时候?
这是我的主管:
-module(data_sup).
-behaviour(supervisor).
%% API
-export([start_link/0,create_bot/3]).
%% Supervisor callbacks
-export([init/1]).
%%-compile(export_all).
%%%===================================================================
%%% API functions
%%%===================================================================
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
RestartStrategy = {simple_one_for_one, 0, 1},
ChildSpec = {cs_fsm, {cs_fsm, start_link, []},
permanent, 2000, worker, [cs_fsm]},
Children = [ChildSpec],
{ok, {RestartStrategy, Children}}.
create_bot(BotId, CNPJ,Pid) ->
supervisor:start_child(?MODULE, [BotId, CNPJ, Pid]).
Pid
是启动监管者并发出命令启动 children 的进程的 Pid。
-module(cs_fsm).
-behaviour(gen_fsm).
-compile(export_all).
-define(SERVER, ?MODULE).
-define(TIMEOUT, 5000).
-record(params, {botId, cnpj, executionId, pid}).
%%%===================================================================
%%% API
%%%===================================================================
start_link(BotId, CNPJ, Pid) ->
io:format("start_link...~n"),
Params = #params{botId = BotId, cnpj = CNPJ, pid = Pid},
gen_fsm:start_link(?MODULE, Params, []).
%%%===================================================================
%%% gen_fsm callbacks
%%%===================================================================
init(Params) ->
io:format("initializing~n"),
process_flag(trap_exit, true),
{ok, requesting_execution, Params, 0}.
requesting_execution(timeout,Params) ->
io:format("erqusting execution"),
{next_state, finished, Params,?TIMEOUT}.
finished(timeout, Params) ->
io:format("finished :)~n"),
{stop, normal, Params}.
terminate(shutdown, _StateName, Params) ->
Params#params.pid ! {terminated, self(),Params},
ok;
terminate(_Reason, _StateName, Params) ->
ok.
我的观点是,如果进程在任何状态下失败,它应该仅在它最后一次被监督者重新启动时才发送消息(根据其重新启动策略)。
如果 gen_fsm
失败,它是否从具有相同状态数据的相同状态重新启动?如果不是,我怎样才能让它发生?
您可以将消息发送到 Module:terminate/3
函数,该函数在 StateName
函数之一 returns {stop,Reason,NewStateData}
时调用,以指示 gen_fsm
应该停止。
gen_fsm
是一个有限状态机,因此您可以决定它如何在状态之间转换。触发最后一个循环的东西也可能在传递给 Module:StateName/3
的 StateData
中设置一些东西,以便处理状态的函数知道它是最后一个循环。除非您提供一些我们可以分析和评论的代码,否则很难给出更具体的答案。
进一步澄清后编辑:
Supervisor 不会通知它的 children 它是什么时候重启它们的,它也不会通知 child 这是最后一次重启。后来这仅仅是因为它不知道这将是最后一次,直到主管进程实际上再次崩溃,而主管进程不可能预测到这一点。只有在 child crashed supervisor 之后才能计算 child 在一段时间内崩溃了多少次,以及是否允许再次重启 child 或者那是最后一次重启并且现在也是监督者去死的时候了
然而,没有什么能阻止 child 注册,例如在 ETS table 中,它重新启动了多少次。但它当然无助于扣除最后一次重启。
编辑 2:
当主管重新启动 child 时,它会使用标准 init
函数从头开始。 child 在崩溃之前的任何先前状态都将丢失。
请注意,崩溃是一种特殊情况,并不总是能够恢复状态,因为崩溃可能已经破坏了状态。与其尝试恢复状态或在完成重启 child 后询问主管,为什么不首先防止崩溃发生呢?您有两个选择:
I. 使用try/catch to catch any exceptional situations and act accordingly. It's possible to catch any error that would otherwise crash the process and cause supervisor to restart it. You can add try/catch
to any entry function inside the gen_fsm
process so that any error condition is caught before it crashes the server. See example function 1 or example function 2:
read() ->
try
try_home() orelse try_path(?MAIN_CFG) orelse
begin io:format("Some Error", []) end
catch
throw:Term -> {error, Term}
end.
try_read(Path) ->
try
file:consult(Path)
catch
error:Error -> {error, Error}
end.
II. 生成一个新进程来处理作业并在进程死亡时捕获 EXIT
信号。这允许 gen_fsm
异步处理作业并以自定义方式处理任何错误(不必像主管那样重新启动流程)。此部分标题为 Error Handling explains how to trap exit
signals from child processes. And this is an example of trapping signals,在 gen_server
中。检查 handle_info
函数,其中包含一些子句以捕获来自 children 进程的不同类型的 EXIT
消息。
init([Cfg, Id, Mode]) ->
process_flag(trap_exit, true),
(...)
handle_info({'EXIT', _Pid, normal}, State) ->
{noreply, State};
handle_info({'EXIT', _Pid, noproc}, State) ->
{noreply, State};
handle_info({'EXIT', Pid, Reason}, State) ->
log_exit(Pid, Reason),
check_done(error, Pid, State);
handle_info(_, State) ->
{noreply, State}.