Search code examples
erlangerlang-otpgen-servererlang-supervisor

Erlang: gen_server in supervisor does not restart at the last known state


I'm working in Erlang with a supervisor that looks like this:

-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]}}.

And a gen_server that looks like this:

-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}}.

The move(Name, {DestX, DestY}) basically moves the location of Name to the new position. Now when I initiate the supervisor and then gen_server and try to crash one of the child processes using erlang:exit(Pid1, die). the process crashes and restarts, as expected, but it starts at the original position where it was started initially (X,Y) instead of the last known position (DestX, DestY). I want to know if the gen_server can store the state in a way that when the process restarts, it resumes at the last known position instead of the original position?


Solution

  • The gen_server itself has a volatile state, in the sense that (as you described in your question) it will go away once the server dies. To preserve the state you will need to use some external mechanisms, such as:

    • an ets table where you keep the state of all your servers indexed by… say… server name or something.
    • persistent_term, again, indexing the information either in a very large map where the keys are the ids of your servers… or by using multiple terms, one per server.

    But, if you end up using any of those solutions, it will now be worth considering if you need the servers at all. If their only responsibility is to manage some state… once that state is stored safely somewhere else, you might want to consider just managing it there directly instead of going through a server process to do the same.