Erlang:主管中的 gen_server 不会在最后已知状态重新启动
Erlang: gen_server in supervisor does not restart at the last known state
我在 Erlang 工作,我的主管是这样的:
-module(a_sup).
-behaviour(supervisor).
%% API
-export([start_link/0, init/1]).
start_link() ->
supervisor:start_link({local,?MODULE}, ?MODULE, []).
init(_Args) ->
RestartStrategy = {simple_one_for_one, 5, 3600},
ChildSpec = {
a_gen_server,
{a_gen_server, start_link, []},
permanent,
brutal_kill,
worker,
[a_gen_server]
},
{ok, {RestartStrategy,[ChildSpec]}}.
还有一个 gen_server 看起来像这样:
-module(a_gen_server).
-behavior(gen_server).
%% API
-export([start_link/2, init/1]).
start_link(Name, {X, Y}) ->
gen_server:start_link({local, Name}, ?MODULE, [Name, {X,Y}], []),
ok.
init([Name, {X,Y}]) ->
process_flag(trap_exit, true),
io:format("~p: position {~p,~p}~n",[Name, X, Y]),
{ok, {X,Y}}.
move(Name, {DestX, DestY}) ->
gen_server:cast(Name, {move, {DestX, DestY}}).
handle_cast({move, {DestX, DestY}}, {X,Y}) ->
{noreply, {DestX, DestY}}.
move(Name, {DestX, DestY})
基本上是把Name的位置移动到新的位置。现在,当我启动主管然后 gen_server 并尝试使用 erlang:exit(Pid1, die).
使其中一个子进程崩溃时,进程崩溃并重新启动,如预期的那样,但它从最初启动的原始位置开始( X,Y) 而不是最后已知的位置 (DestX, DestY)。我想知道 gen_server 是否可以以一种方式存储状态,当进程重新启动时,它会在最后一个已知位置而不是原始位置恢复?
gen_server
本身有一个 volatile 状态,从某种意义上说(正如你在问题中所描述的那样)一旦服务器死机它就会消失。
要保留状态,您需要使用一些外部机制,例如:
- an
ets
table 在这里你保存所有服务器的状态索引...比如...服务器名称或其他东西。
persistent_term
,同样,在一个非常大的地图中索引信息,其中键是您的服务器的 ID……或者使用多个术语,每个服务器一个。
但是,如果您最终使用了这些解决方案中的任何一个,现在就值得考虑是否需要服务器。如果他们唯一的职责是管理某些状态……一旦该状态安全地存储在其他地方,您可能需要考虑直接在那里管理它,而不是通过服务器进程来执行相同的操作。
我在 Erlang 工作,我的主管是这样的:
-module(a_sup).
-behaviour(supervisor).
%% API
-export([start_link/0, init/1]).
start_link() ->
supervisor:start_link({local,?MODULE}, ?MODULE, []).
init(_Args) ->
RestartStrategy = {simple_one_for_one, 5, 3600},
ChildSpec = {
a_gen_server,
{a_gen_server, start_link, []},
permanent,
brutal_kill,
worker,
[a_gen_server]
},
{ok, {RestartStrategy,[ChildSpec]}}.
还有一个 gen_server 看起来像这样:
-module(a_gen_server).
-behavior(gen_server).
%% API
-export([start_link/2, init/1]).
start_link(Name, {X, Y}) ->
gen_server:start_link({local, Name}, ?MODULE, [Name, {X,Y}], []),
ok.
init([Name, {X,Y}]) ->
process_flag(trap_exit, true),
io:format("~p: position {~p,~p}~n",[Name, X, Y]),
{ok, {X,Y}}.
move(Name, {DestX, DestY}) ->
gen_server:cast(Name, {move, {DestX, DestY}}).
handle_cast({move, {DestX, DestY}}, {X,Y}) ->
{noreply, {DestX, DestY}}.
move(Name, {DestX, DestY})
基本上是把Name的位置移动到新的位置。现在,当我启动主管然后 gen_server 并尝试使用 erlang:exit(Pid1, die).
使其中一个子进程崩溃时,进程崩溃并重新启动,如预期的那样,但它从最初启动的原始位置开始( X,Y) 而不是最后已知的位置 (DestX, DestY)。我想知道 gen_server 是否可以以一种方式存储状态,当进程重新启动时,它会在最后一个已知位置而不是原始位置恢复?
gen_server
本身有一个 volatile 状态,从某种意义上说(正如你在问题中所描述的那样)一旦服务器死机它就会消失。
要保留状态,您需要使用一些外部机制,例如:
- an
ets
table 在这里你保存所有服务器的状态索引...比如...服务器名称或其他东西。 persistent_term
,同样,在一个非常大的地图中索引信息,其中键是您的服务器的 ID……或者使用多个术语,每个服务器一个。
但是,如果您最终使用了这些解决方案中的任何一个,现在就值得考虑是否需要服务器。如果他们唯一的职责是管理某些状态……一旦该状态安全地存储在其他地方,您可能需要考虑直接在那里管理它,而不是通过服务器进程来执行相同的操作。