Now we can crash ggs_coordinator without it affecting the clients.
This commit is contained in:
parent
f6bb2328a1
commit
87df33fd47
4 changed files with 100 additions and 12 deletions
|
@ -53,13 +53,26 @@ remove_player(_From, _Player) ->
|
|||
%gen_server:cast(ggs_coordinator, {remove_player, Player}).
|
||||
ggs_logger:not_implemented().
|
||||
|
||||
%% Just to shorten the name
|
||||
back_up(State) ->
|
||||
ggs_coordinator_backup:back_up(State),
|
||||
State.
|
||||
|
||||
%% gen_server callbacks
|
||||
|
||||
init([]) ->
|
||||
{ok, #co_state{}}.
|
||||
% Restore old state from backup if there is old state stored there
|
||||
case ggs_coordinator_backup:retrieve() of
|
||||
no_state_stored ->
|
||||
io:format("No old state stored.. Creating new!~n"),
|
||||
{ok, #co_state{}};
|
||||
State ->
|
||||
{ok, State}
|
||||
end.
|
||||
|
||||
handle_call(join_lobby, _From, State) ->
|
||||
Token = helpers:get_new_token(),
|
||||
back_up(State),
|
||||
{reply, {ok, Token}, State};
|
||||
|
||||
handle_call({join_table, Table}, From, State) ->
|
||||
|
@ -68,19 +81,23 @@ handle_call({join_table, Table}, From, State) ->
|
|||
case lists:keyfind(Table, 1, Tables) of
|
||||
{_TableID, TablePID} ->
|
||||
ggs_table:add_player(TablePID, FromPlayer),
|
||||
back_up(State),
|
||||
{reply, {ok, TablePID}, State};
|
||||
false ->
|
||||
back_up(State),
|
||||
{reply, {error, no_such_table}, State}
|
||||
end;
|
||||
|
||||
handle_call({create_table, {force, TableID}}, From, State) ->
|
||||
TableIDMap = State#co_state.player_table_map,
|
||||
Tables = State#co_state.tables,
|
||||
NewTableProc = ggs_table:start_link(),
|
||||
{reply, {ok, TableID}, State#co_state{
|
||||
player_table_map = [{From, TableID} | TableIDMap],
|
||||
tables = [{TableID, NewTableProc} | Tables]
|
||||
}};
|
||||
NewTableProc = ggs_table:start(), % With start_link, the table dies with the coordinator
|
||||
NewState = State#co_state{
|
||||
player_table_map = [{From, TableID} | TableIDMap],
|
||||
tables = [{TableID, NewTableProc} | Tables]
|
||||
},
|
||||
back_up(NewState),
|
||||
{reply, {ok, TableID}, NewState};
|
||||
|
||||
handle_call(_Message, _From, State) ->
|
||||
{noreply, State}.
|
||||
|
|
65
src/ggs_coordinator_backup.erl
Normal file
65
src/ggs_coordinator_backup.erl
Normal file
|
@ -0,0 +1,65 @@
|
|||
-module(ggs_coordinator_backup).
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
%% API Exports
|
||||
-export([start_link/0, stop/1]).
|
||||
-export([back_up/1, retrieve/0]).
|
||||
|
||||
%% gen_server callback exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
|
||||
code_change/3]).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
%% @doc This module is repsponsible for keeping a backup of the coodinator
|
||||
%% at all times. At any point in time a backup can be restored from this
|
||||
%% module.
|
||||
%% This module is started by the root supervisor, and is restarted when it
|
||||
%% crashes. Upon a crash, the backup state is lost in this module, and must
|
||||
%% be filled in from the ggs_coordinator.
|
||||
|
||||
%% @doc Start a new ggs_coordinator backup instance, and register it under
|
||||
%% this name. This means that there can only be one instance of this module
|
||||
%% running.
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
|
||||
|
||||
%% @doc Stops the server with the specified reason.
|
||||
%% @spec stop(Reason) -> ok.
|
||||
%% Reason = String
|
||||
stop(_Reason) -> ggs_logger:not_implemented().
|
||||
|
||||
%% API
|
||||
back_up(State) ->
|
||||
gen_server:cast(?SERVER, State).
|
||||
|
||||
%% @doc Retrieve the state stored in this server. If there is a state stored
|
||||
%% here, it is returned to the caller. If the backup server does not have a
|
||||
%% state stored, it will return the no_state_stored atom.
|
||||
retrieve() ->
|
||||
gen_server:call(?SERVER, retrieve).
|
||||
|
||||
%% gen_server callbacks
|
||||
|
||||
%% @doc Initiate the server. This is called from gen_server
|
||||
init([]) ->
|
||||
{ok, no_state_stored}.
|
||||
|
||||
handle_call(retrieve, _From, State) ->
|
||||
{reply, State, State}.
|
||||
|
||||
handle_cast(NewState, _State) ->
|
||||
{noreply, NewState}.
|
||||
|
||||
handle_info(Msg, State) ->
|
||||
io:format("Received out of bounds message! "),
|
||||
erlang:display(Msg),
|
||||
io:format("~n"),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(normal, _State) ->
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
|
@ -26,7 +26,14 @@ init([Port]) ->
|
|||
worker,
|
||||
[ggs_coordinator]
|
||||
},
|
||||
Children = [Dispatcher, Coordinator],
|
||||
Coordinator_backup = {ggs_coordinator_backup,
|
||||
{ggs_coordinator_backup, start_link, []},
|
||||
permanent,
|
||||
2000,
|
||||
worker,
|
||||
[ggs_coordinator_backup]
|
||||
},
|
||||
Children = [Dispatcher, Coordinator_backup, Coordinator],
|
||||
|
||||
RestartStrategy = { one_for_one, % Restart only crashing child
|
||||
10, % Allow ten crashes per..
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
-record(state, { players, game_vm } ).
|
||||
|
||||
%% API
|
||||
-export([start_link/0,
|
||||
-export([start/0,
|
||||
add_player/2,
|
||||
remove_player/2,
|
||||
stop/1,
|
||||
|
@ -24,8 +24,8 @@
|
|||
% API implementation
|
||||
|
||||
% @doc returns a new table
|
||||
start_link() ->
|
||||
{ok, Pid} = gen_server:start_link(?MODULE, [], []),
|
||||
start() ->
|
||||
{ok, Pid} = gen_server:start(?MODULE, [], []),
|
||||
Pid.
|
||||
|
||||
%% @private
|
||||
|
@ -56,14 +56,13 @@ notify_all_players(Table, Message) ->
|
|||
gen_server:cast(Table, {notify_all_players, Message}).
|
||||
|
||||
notify_game(Table, From, Message) ->
|
||||
erlang:display(Table),
|
||||
io:format("~n"),
|
||||
gen_server:cast(Table, {notify_game, Message, From}).
|
||||
|
||||
%% ----------------------------------------------------------------------
|
||||
|
||||
%% @private
|
||||
init([]) ->
|
||||
process_flag(trap_exit, true),
|
||||
GameVM = ggs_gamevm_e:start_link(self()), %% @TODO: Temporary erlang gamevm
|
||||
{ok, #state {
|
||||
game_vm = GameVM,
|
||||
|
|
Reference in a new issue