Skip to content

Commit f0b6954

Browse files
committed
Update and add missing supervisor types, specs and module doc
- Updates some types to match OTP, and adds some others, including exports types for `startchild_ret/0` and `startlink_ret/0`. - Adds a module doc section listing differences with OTP supervisor. - Adds specs to all public functions, and marks callbacks as hidden functions so they are not included in published user API docs. - Adds todos where child and supervisor event reports should be logged Signed-off-by: Winford <[email protected]>
1 parent ab4937d commit f0b6954

File tree

1 file changed

+83
-5
lines changed

1 file changed

+83
-5
lines changed

libs/estdlib/src/supervisor.erl

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020

2121
-module(supervisor).
2222

23+
%%-----------------------------------------------------------------------------
24+
%% @doc An implementation of the Erlang/OTP supervisor interface.
25+
%%
26+
%% This module implements a strict subset of the Erlang/OTP supervisor
27+
%% interface, supporting operations for local creation and management of
28+
%% supervisor instances.
29+
%%
30+
%% This module is designed to be API-compatible with supervisor, with exceptions
31+
%% noted below.
32+
%%
33+
%% Caveats:
34+
%% <ul>
35+
%% <li>Support only for locally named procs</li>
36+
%% <li>No support for simple_one_for_one or one_for_rest strategies</li>
37+
%% <li>No support for hibernate</li>
38+
%% <li>No support for automatic shutdown</li>
39+
%% </ul>
40+
%% @end
41+
%%-----------------------------------------------------------------------------
42+
2343
-behavior(gen_server).
2444

2545
-export([
@@ -43,6 +63,8 @@
4363

4464
-export_type([
4565
child_spec/0,
66+
startchild_ret/0,
67+
startlink_ret/0,
4668
strategy/0,
4769
sup_flags/0
4870
]).
@@ -53,7 +75,9 @@
5375
| temporary
5476
| {terminating, permanent | transient | temporary, gen_server:from()}.
5577
-type shutdown() :: brutal_kill | timeout().
56-
-type child_type() :: worker | supervisor.
78+
-type worker() :: worker | supervisor.
79+
-type child_id() :: term().
80+
-type child() :: undefined | pid().
5781

5882
-type strategy() :: one_for_all | one_for_one.
5983
-type sup_flags() ::
@@ -70,25 +94,38 @@
7094
start := {module(), atom(), [any()]},
7195
restart => restart(),
7296
shutdown => shutdown(),
73-
type => child_type(),
97+
type => worker(),
7498
modules => [module()] | dynamic
7599
}
76100
| {
77101
Id :: any(),
78102
StartFunc :: {module(), atom(), [any()]},
79103
Restart :: restart(),
80104
Shutdown :: shutdown(),
81-
Type :: child_type(),
105+
Type :: worker(),
82106
Modules :: [module()] | dynamic
83107
}.
84108

109+
-type startlink_ret() :: {ok, pid()} | ignore | {error, startlink_err()}.
110+
-type startlink_err() :: {already_started, pid()} | {shutdown, term()} | term().
111+
-type startchild_ret() ::
112+
{ok, Child :: child()} | {ok, Child :: child(), Info :: term()} | {error, startchild_err()}.
113+
-type startchild_err() :: already_present | {already_started, Child :: child()} | term().
114+
-type sup_name() :: {local, Name :: atom()}.
115+
-type sup_ref() ::
116+
(Name :: atom())
117+
| {Name :: atom(), Node :: node()}
118+
| {global, Name :: term()}
119+
| {via, Module :: module(), Name :: any()}
120+
| pid().
121+
85122
-record(child, {
86123
pid = undefined :: pid() | undefined | {restarting, pid()} | {restarting, undefined},
87124
id :: any(),
88125
start :: {module(), atom(), [any()] | undefined},
89126
restart :: restart(),
90127
shutdown :: shutdown(),
91-
type :: child_type(),
128+
type :: worker(),
92129
modules = [] :: [module()] | dynamic
93130
}).
94131
%% note: the list of children should always be kept in order, with first to start at the head.
@@ -108,30 +145,59 @@
108145
%% could be used to set a sane default for the platform (OTP uses 1000).
109146
-define(STALE_RESTART_LIMIT, 100).
110147

148+
-spec start_link(Module :: module(), Args :: [any()]) -> startlink_ret().
111149
start_link(Module, Args) ->
112150
gen_server:start_link(?MODULE, {Module, Args}, []).
113151

152+
-spec start_link(SupName :: sup_name(), Module :: module(), Args :: [any()]) -> startlink_ret().
114153
start_link(SupName, Module, Args) ->
115154
gen_server:start_link(SupName, ?MODULE, {Module, Args}, []).
116155

156+
-spec start_child(Supervisor :: sup_ref(), ChildSpec :: child_spec()) -> startchild_ret().
117157
start_child(Supervisor, ChildSpec) ->
118158
gen_server:call(Supervisor, {start_child, ChildSpec}).
119159

160+
-spec terminate_child(Supervisor :: sup_ref(), ChildId :: any()) -> ok | {error, not_found}.
120161
terminate_child(Supervisor, ChildId) ->
121162
gen_server:call(Supervisor, {terminate_child, ChildId}).
122163

164+
-spec restart_child(Supervisor :: sup_ref(), ChildId :: any()) ->
165+
{ok, Child :: child()}
166+
| {ok, Child :: child(), Info :: term()}
167+
| {error, Reason :: running | restarting | not_found | term()}.
123168
restart_child(Supervisor, ChildId) ->
124169
gen_server:call(Supervisor, {restart_child, ChildId}).
125170

171+
-spec delete_child(Supervisor :: sup_ref(), ChildId :: any()) ->
172+
ok | {error, Reason :: running | restarting | not_found}.
126173
delete_child(Supervisor, ChildId) ->
127174
gen_server:call(Supervisor, {delete_child, ChildId}).
128175

176+
-spec which_children(Supervisor :: sup_ref()) ->
177+
[
178+
{
179+
Id :: child_id() | undefined,
180+
Child :: child() | restarting,
181+
Type :: worker(),
182+
Modules :: [module()]
183+
}
184+
].
129185
which_children(Supervisor) ->
130186
gen_server:call(Supervisor, which_children).
131187

188+
-spec count_children(Supervisor :: sup_ref()) ->
189+
[
190+
{specs, ChildSpecCount :: non_neg_integer()}
191+
| {active, ActiveProcessCount :: non_neg_integer()}
192+
| {supervisors, ChildSupervisorCount :: non_neg_integer()}
193+
| {workers, ChildWorkerCount :: non_neg_integer()}
194+
].
132195
count_children(Supervisor) ->
133196
gen_server:call(Supervisor, count_children).
134197

198+
% @hidden
199+
-spec init({Mod :: module(), Args :: [any()]}) ->
200+
{ok, State :: #state{}} | {stop, {bad_return, {Mod :: module(), init, Reason :: term()}}}.
135201
init({Mod, Args}) ->
136202
erlang:process_flag(trap_exit, true),
137203
case Mod:init(Args) of
@@ -155,6 +221,7 @@ init({Mod, Args}) ->
155221
NewChildren = start_children(State#state.children, []),
156222
{ok, State#state{children = NewChildren}};
157223
Error ->
224+
% TODO: log supervisor init failure
158225
{stop, {bad_return, {Mod, init, Error}}}
159226
end.
160227

@@ -196,13 +263,17 @@ child_spec_to_record(#{id := ChildId, start := MFA} = ChildMap) ->
196263
modules = Modules
197264
}.
198265

266+
% @hidden
267+
-spec init_state(ChildSpecs :: [child_spec()], State :: #state{}) -> State :: #state{}.
199268
init_state([ChildSpec | T], State) ->
200269
Child = child_spec_to_record(ChildSpec),
201270
NewChildren = [Child | State#state.children],
202271
init_state(T, State#state{children = NewChildren});
203272
init_state([], State) ->
204273
State#state{children = lists:reverse(State#state.children)}.
205274

275+
-spec start_children(ChildSpecs :: [child_spec()], State :: #state{}) ->
276+
ChildSpecs :: [child_spec()].
206277
start_children([Child | T], StartedC) ->
207278
case try_start(Child) of
208279
{ok, Pid, _Result} ->
@@ -212,6 +283,7 @@ start_children([], StartedC) ->
212283
%% We should always keep the start list in order for later one_for_all restarts.
213284
lists:reverse(StartedC).
214285

286+
% @hidden
215287
handle_call({start_child, ChildSpec}, _From, #state{children = Children} = State) ->
216288
Child = child_spec_to_record(ChildSpec),
217289
#child{id = ID} = Child,
@@ -286,10 +358,13 @@ handle_call(count_children, _From, #state{children = Children} = State) ->
286358
Reply = [{specs, Specs}, {active, Active}, {supervisors, Supers}, {workers, Workers}],
287359
{reply, Reply, State}.
288360

361+
% @hidden
289362
handle_cast(_Msg, State) ->
290363
{noreply, State}.
291364

365+
% @hidden
292366
handle_info({'EXIT', Pid, Reason}, State) ->
367+
% TODO: log crash report
293368
handle_child_exit(Pid, Reason, State);
294369
handle_info({ensure_killed, Pid}, State) ->
295370
case lists:keyfind(Pid, #child.pid, State#state.children) of
@@ -327,15 +402,17 @@ handle_info({try_again_restart, Id}, State) ->
327402
),
328403
{noreply, State1#state{children = UpdatedChildren}};
329404
{error, {_, _}} ->
405+
% TODO: log crash report
330406
{noreply, State1, {timeout, 0, {try_again_restart, Id}}}
331407
end;
332408
{shutdown, State1} ->
333409
RemainingChildren = lists:keydelete(Id, #child.id, State1#state.children),
410+
% TODO: log supervisor shutdown
334411
{stop, shutdown, State1#state{children = RemainingChildren}}
335412
end
336413
end;
337414
handle_info(_Msg, State) ->
338-
%TODO: log unexpected message
415+
%TODO: log unexpected message to debug
339416
{noreply, State}.
340417

341418
%% @hidden
@@ -372,6 +449,7 @@ handle_child_exit(Pid, Reason, State) ->
372449
RemainingChildren = lists:keydelete(
373450
Pid, #child.pid, State1#state.children
374451
),
452+
% TODO: log supervisor shutdown
375453
{stop, shutdown, State1#state{children = RemainingChildren}}
376454
end;
377455
false ->

0 commit comments

Comments
 (0)