Permalink
Browse files

agner_repo_servers cleanup after themselves properly now

  • Loading branch information...
1 parent fb9af35 commit db2527cfa2133a0679d8da999d1c37567151b49f @yrashk yrashk committed Feb 4, 2011
Showing with 44 additions and 6 deletions.
  1. +41 −3 src/agner_app.erl
  2. +1 −1 src/agner_repo_server.erl
  3. +1 −1 src/agner_repo_server_sup.erl
  4. +1 −1 src/agner_sup.erl
View
44 src/agner_app.erl
@@ -4,14 +4,52 @@
-behaviour(application).
%% Application callbacks
--export([start/2, stop/1]).
+-export([start/2, stop/1, prep_stop/1]).
%% ===================================================================
%% Application callbacks
%% ===================================================================
start(_StartType, _StartArgs) ->
- agner_sup:start_link().
+ {ok, Pid} = agner_sup:start_link(),
+ {ok, Pid, []}.
-stop(_State) ->
+%% The reason for the code below is that we have a simple_one_for_one supervisor
+%% (agner_repo_server_sup) and according to supervisor's documentation:
+%% "Important note on simple-one-for-one supervisors: The dynamically created child
+%% processes of a simple-one-for-one supervisor are not explicitly killed, regardless of
+%% shutdown strategy, but are expected to terminate when the supervisor does (that is, when
+%% an exit signal from the parent process is received)."
+%% Since agner_repo_server is actually trapping exits to run terminate/2 to clean up
+%% after itself, some (sometimes may be all of them) of its instances *do* receive an EXIT
+%% from the supervisor and get their terminate/2 callbacks called; but since the supervisor
+%% is not explicitly killing them and not waiting for them to die, it means by the time
+%% supervisor is dead, some of them *may have* went through terminate/2 and some may have not,
+%% but since the top supervisor was wrapping up its business and dying as well, the application
+%% master (as a group leader) was going through killing all remaining children regardless of whether
+%% they finished their business or not (and by business we mean terminate/2 here), and thus
+%% preventing their proper cleanup.
+
+%% So what we are doing here is we're memorizing the list of children that are about to terminate
+%% in prep_stop/1 and put them into the application state, and once top supervisor is dead and
+%% stop/1 is called, we pick them up from the state, setup monitors on them and wait until every
+%% one of them is DOWN (and that means the stuff is now cleaned up)
+
+%% This would probably take a whole lot more time to figure out if Fred Hebert had't offered
+%% his help to brainstorm this problem through. Merci pour l'aide!
+
+
+prep_stop(_) ->
+ lists:map(fun ({_,P,_,_}) -> P end, supervisor:which_children(agner_repo_server_sup)).
+
+stop(State) ->
+ stop_loop(lists:map(fun (P) -> monitor(process, P) end, State)),
ok.
+
+stop_loop([]) ->
+ ok;
+stop_loop([Ref|Rest]) ->
+ receive
+ {'DOWN',Ref,process,_,_} ->
+ stop_loop(Rest)
+ end.
View
2 src/agner_repo_server.erl
@@ -199,7 +199,7 @@ handle_info(_Info, State) ->
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, #state{ directory = Directory }) when is_list(Directory) ->
- os:cmd("echo X >> deleted && rm -rf " ++ Directory),
+ os:cmd("rm -rf " ++ Directory),
ok;
terminate(_Reason, _State) ->
ok.
View
2 src/agner_repo_server_sup.erl
@@ -10,7 +10,7 @@
-export([init/1]).
%% Helper macro for declaring children of supervisor
--define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
+-define(CHILD(I, Type), {I, {I, start_link, []}, transient, 5000, Type, [I]}).
%% ===================================================================
%% API functions
View
2 src/agner_sup.erl
@@ -26,7 +26,7 @@ start_link() ->
%% ===================================================================
init([]) ->
- {ok, { {one_for_one, 5, 10}, [
+ {ok, { {one_for_all, 5, 10}, [
?SUP(agner_repo_server_sup, infinity),
?CHILD(agner_server, worker)
]} }.

0 comments on commit db2527c

Please sign in to comment.