Skip to content

Commit 11474b5

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 de0dc30 commit 11474b5

File tree

1 file changed

+85
-6
lines changed

1 file changed

+85
-6
lines changed

libs/estdlib/src/supervisor.erl

Lines changed: 85 additions & 6 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,8 +63,13 @@
4363

4464
-export_type([
4565
child_spec/0,
66+
startchild_ret/0,
67+
startlink_ret/0,
68+
startlink_err/0,
4669
strategy/0,
47-
sup_flags/0
70+
sup_flags/0,
71+
sup_name/0,
72+
sup_ref/0
4873
]).
4974

5075
-type restart() ::
@@ -53,7 +78,9 @@
5378
| temporary
5479
| {terminating, permanent | transient | temporary, gen_server:from()}.
5580
-type shutdown() :: brutal_kill | timeout().
56-
-type child_type() :: worker | supervisor.
81+
-type worker() :: worker | supervisor.
82+
-type child_id() :: term().
83+
-type child() :: undefined | pid().
5784

5885
-type strategy() :: one_for_all | one_for_one.
5986
-type sup_flags() ::
@@ -70,25 +97,36 @@
7097
start := {module(), atom(), [any()]},
7198
restart => restart(),
7299
shutdown => shutdown(),
73-
type => child_type(),
100+
type => worker(),
74101
modules => [module()] | dynamic
75102
}
76103
| {
77104
Id :: any(),
78105
StartFunc :: {module(), atom(), [any()]},
79106
Restart :: restart(),
80107
Shutdown :: shutdown(),
81-
Type :: child_type(),
108+
Type :: worker(),
82109
Modules :: [module()] | dynamic
83110
}.
84111

112+
-type startlink_ret() :: {ok, pid()} | ignore | {error, startlink_err()}.
113+
-type startlink_err() :: {already_started, pid()} | {shutdown, term()} | term().
114+
-type startchild_ret() ::
115+
{ok, Child :: child()} | {ok, Child :: child(), Info :: term()} | {error, startchild_err()}.
116+
-type startchild_err() :: already_present | {already_started, Child :: child()} | term().
117+
-type sup_name() :: {local, Name :: atom()}.
118+
-type sup_ref() ::
119+
(Name :: atom())
120+
| {Name :: atom(), Node :: node()}
121+
| pid().
122+
85123
-record(child, {
86124
pid = undefined :: pid() | undefined | {restarting, pid()} | {restarting, undefined},
87125
id :: any(),
88126
start :: {module(), atom(), [any()] | undefined},
89127
restart :: restart(),
90128
shutdown :: shutdown(),
91-
type :: child_type(),
129+
type :: worker(),
92130
modules = [] :: [module()] | dynamic
93131
}).
94132
%% note: the list of children should always be kept in order, with last to start at the head.
@@ -110,30 +148,59 @@
110148
-define(DEFAULT_INTENSITY, 1).
111149
-define(DEFAULT_PERIOD, 5).
112150

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

155+
-spec start_link(SupName :: sup_name(), Module :: module(), Args :: [any()]) -> startlink_ret().
116156
start_link(SupName, Module, Args) ->
117157
gen_server:start_link(SupName, ?MODULE, {Module, Args}, []).
118158

159+
-spec start_child(Supervisor :: sup_ref(), ChildSpec :: child_spec()) -> startchild_ret().
119160
start_child(Supervisor, ChildSpec) ->
120161
gen_server:call(Supervisor, {start_child, ChildSpec}).
121162

163+
-spec terminate_child(Supervisor :: sup_ref(), ChildId :: any()) -> ok | {error, not_found}.
122164
terminate_child(Supervisor, ChildId) ->
123165
gen_server:call(Supervisor, {terminate_child, ChildId}).
124166

167+
-spec restart_child(Supervisor :: sup_ref(), ChildId :: any()) ->
168+
{ok, Child :: child()}
169+
| {ok, Child :: child(), Info :: term()}
170+
| {error, Reason :: running | restarting | not_found | term()}.
125171
restart_child(Supervisor, ChildId) ->
126172
gen_server:call(Supervisor, {restart_child, ChildId}).
127173

174+
-spec delete_child(Supervisor :: sup_ref(), ChildId :: any()) ->
175+
ok | {error, Reason :: running | restarting | not_found}.
128176
delete_child(Supervisor, ChildId) ->
129177
gen_server:call(Supervisor, {delete_child, ChildId}).
130178

179+
-spec which_children(Supervisor :: sup_ref()) ->
180+
[
181+
{
182+
Id :: child_id() | undefined,
183+
Child :: child() | restarting,
184+
Type :: worker(),
185+
Modules :: [module()]
186+
}
187+
].
131188
which_children(Supervisor) ->
132189
gen_server:call(Supervisor, which_children).
133190

191+
-spec count_children(Supervisor :: sup_ref()) ->
192+
[
193+
{specs, ChildSpecCount :: non_neg_integer()}
194+
| {active, ActiveProcessCount :: non_neg_integer()}
195+
| {supervisors, ChildSupervisorCount :: non_neg_integer()}
196+
| {workers, ChildWorkerCount :: non_neg_integer()}
197+
].
134198
count_children(Supervisor) ->
135199
gen_server:call(Supervisor, count_children).
136200

201+
% @hidden
202+
-spec init({Mod :: module(), Args :: [any()]}) ->
203+
{ok, State :: #state{}} | {stop, {bad_return, {Mod :: module(), init, Reason :: term()}}}.
137204
init({Mod, Args}) ->
138205
erlang:process_flag(trap_exit, true),
139206
case Mod:init(Args) of
@@ -157,6 +224,7 @@ init({Mod, Args}) ->
157224
NewChildren = start_children(State#state.children, []),
158225
{ok, State#state{children = NewChildren}};
159226
Error ->
227+
% TODO: log supervisor init failure
160228
{stop, {bad_return, {Mod, init, Error}}}
161229
end.
162230

@@ -198,13 +266,17 @@ child_spec_to_record(#{id := ChildId, start := MFA} = ChildMap) ->
198266
modules = Modules
199267
}.
200268

269+
% @hidden
270+
-spec init_state(ChildSpecs :: [child_spec()], State :: #state{}) -> State :: #state{}.
201271
init_state([ChildSpec | T], State) ->
202272
Child = child_spec_to_record(ChildSpec),
203273
NewChildren = [Child | State#state.children],
204274
init_state(T, State#state{children = NewChildren});
205275
init_state([], State) ->
206276
State#state{children = lists:reverse(State#state.children)}.
207277

278+
-spec start_children(ChildSpecs :: [child_spec()], State :: #state{}) ->
279+
ChildSpecs :: [child_spec()].
208280
start_children([Child | T], StartedC) ->
209281
case try_start(Child) of
210282
{ok, Pid, _Result} ->
@@ -213,6 +285,7 @@ start_children([Child | T], StartedC) ->
213285
start_children([], StartedC) ->
214286
StartedC.
215287

288+
% @hidden
216289
handle_call({start_child, ChildSpec}, _From, #state{children = Children} = State) ->
217290
Child = child_spec_to_record(ChildSpec),
218291
#child{id = ID} = Child,
@@ -287,10 +360,13 @@ handle_call(count_children, _From, #state{children = Children} = State) ->
287360
Reply = [{specs, Specs}, {active, Active}, {supervisors, Supers}, {workers, Workers}],
288361
{reply, Reply, State}.
289362

363+
% @hidden
290364
handle_cast(_Msg, State) ->
291365
{noreply, State}.
292366

367+
% @hidden
293368
handle_info({'EXIT', Pid, Reason}, State) ->
369+
% TODO: log crash report
294370
handle_child_exit(Pid, Reason, State);
295371
handle_info({ensure_killed, Pid}, State) ->
296372
case lists:keyfind(Pid, #child.pid, State#state.children) of
@@ -330,17 +406,19 @@ handle_info({try_again_restart, Id}, State) ->
330406
),
331407
{noreply, State1#state{children = UpdatedChildren}};
332408
{error, {_, _}} ->
409+
% TODO: log crash report
333410
{noreply, State1, {timeout, 0, {try_again_restart, Id}}}
334411
end;
335412
{shutdown, State1} ->
336413
RemainingChildren = lists:keydelete(Id, #child.id, State1#state.children),
414+
% TODO: log supervisor shutdown
337415
{stop, shutdown, State1#state{children = RemainingChildren}}
338416
end
339417
end;
340418
handle_info({restart_many_children, [#child{pid = undefined} = _Child | Children]}, State) ->
341419
{noreply, State, {timeout, 0, {restart_many_children, Children}}};
342420
handle_info(_Msg, State) ->
343-
%TODO: log unexpected message
421+
%TODO: log unexpected message to debug
344422
{noreply, State}.
345423

346424
%% @hidden
@@ -377,6 +455,7 @@ handle_child_exit(Pid, Reason, State) ->
377455
RemainingChildren = lists:keydelete(
378456
Pid, #child.pid, State1#state.children
379457
),
458+
% TODO: log supervisor shutdown
380459
{stop, shutdown, State1#state{children = RemainingChildren}}
381460
end;
382461
false ->

0 commit comments

Comments
 (0)