Skip to content

Commit 3c8849a

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 32ae410 commit 3c8849a

File tree

1 file changed

+87
-6
lines changed

1 file changed

+87
-6
lines changed

libs/estdlib/src/supervisor.erl

Lines changed: 87 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,38 @@
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+
| {global, Name :: term()}
122+
| {via, Module :: module(), Name :: any()}
123+
| pid().
124+
85125
-record(child, {
86126
pid = undefined :: pid() | undefined | {restarting, pid()} | {restarting, undefined},
87127
id :: any(),
88128
start :: {module(), atom(), [any()] | undefined},
89129
restart :: restart(),
90130
shutdown :: shutdown(),
91-
type :: child_type(),
131+
type :: worker(),
92132
modules = [] :: [module()] | dynamic
93133
}).
94134
%% note: the list of children should always be kept in order, with last to start at the head.
@@ -108,30 +148,59 @@
108148
%% could be used to set a sane default for the platform (OTP uses 1000).
109149
-define(STALE_RESTART_LIMIT, 100).
110150

151+
-spec start_link(Module :: module(), Args :: [any()]) -> startlink_ret().
111152
start_link(Module, Args) ->
112153
gen_server:start_link(?MODULE, {Module, Args}, []).
113154

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

159+
-spec start_child(Supervisor :: sup_ref(), ChildSpec :: child_spec()) -> startchild_ret().
117160
start_child(Supervisor, ChildSpec) ->
118161
gen_server:call(Supervisor, {start_child, ChildSpec}).
119162

163+
-spec terminate_child(Supervisor :: sup_ref(), ChildId :: any()) -> ok | {error, not_found}.
120164
terminate_child(Supervisor, ChildId) ->
121165
gen_server:call(Supervisor, {terminate_child, ChildId}).
122166

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()}.
123171
restart_child(Supervisor, ChildId) ->
124172
gen_server:call(Supervisor, {restart_child, ChildId}).
125173

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

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+
].
129188
which_children(Supervisor) ->
130189
gen_server:call(Supervisor, which_children).
131190

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+
].
132198
count_children(Supervisor) ->
133199
gen_server:call(Supervisor, count_children).
134200

201+
% @hidden
202+
-spec init({Mod :: module(), Args :: [any()]}) ->
203+
{ok, State :: #state{}} | {stop, {bad_return, {Mod :: module(), init, Reason :: term()}}}.
135204
init({Mod, Args}) ->
136205
erlang:process_flag(trap_exit, true),
137206
case Mod:init(Args) of
@@ -155,6 +224,7 @@ init({Mod, Args}) ->
155224
NewChildren = start_children(State#state.children, []),
156225
{ok, State#state{children = NewChildren}};
157226
Error ->
227+
% TODO: log supervisor init failure
158228
{stop, {bad_return, {Mod, init, Error}}}
159229
end.
160230

@@ -196,13 +266,17 @@ child_spec_to_record(#{id := ChildId, start := MFA} = ChildMap) ->
196266
modules = Modules
197267
}.
198268

269+
% @hidden
270+
-spec init_state(ChildSpecs :: [child_spec()], State :: #state{}) -> State :: #state{}.
199271
init_state([ChildSpec | T], State) ->
200272
Child = child_spec_to_record(ChildSpec),
201273
NewChildren = [Child | State#state.children],
202274
init_state(T, State#state{children = NewChildren});
203275
init_state([], State) ->
204276
State#state{children = lists:reverse(State#state.children)}.
205277

278+
-spec start_children(ChildSpecs :: [child_spec()], State :: #state{}) ->
279+
ChildSpecs :: [child_spec()].
206280
start_children([Child | T], StartedC) ->
207281
case try_start(Child) of
208282
{ok, Pid, _Result} ->
@@ -211,6 +285,7 @@ start_children([Child | T], StartedC) ->
211285
start_children([], StartedC) ->
212286
StartedC.
213287

288+
% @hidden
214289
handle_call({start_child, ChildSpec}, _From, #state{children = Children} = State) ->
215290
Child = child_spec_to_record(ChildSpec),
216291
#child{id = ID} = Child,
@@ -285,10 +360,13 @@ handle_call(count_children, _From, #state{children = Children} = State) ->
285360
Reply = [{specs, Specs}, {active, Active}, {supervisors, Supers}, {workers, Workers}],
286361
{reply, Reply, State}.
287362

363+
% @hidden
288364
handle_cast(_Msg, State) ->
289365
{noreply, State}.
290366

367+
% @hidden
291368
handle_info({'EXIT', Pid, Reason}, State) ->
369+
% TODO: log crash report
292370
handle_child_exit(Pid, Reason, State);
293371
handle_info({ensure_killed, Pid}, State) ->
294372
case lists:keyfind(Pid, #child.pid, State#state.children) of
@@ -328,17 +406,19 @@ handle_info({try_again_restart, Id}, State) ->
328406
),
329407
{noreply, State1#state{children = UpdatedChildren}};
330408
{error, {_, _}} ->
409+
% TODO: log crash report
331410
{noreply, State1, {timeout, 0, {try_again_restart, Id}}}
332411
end;
333412
{shutdown, State1} ->
334413
RemainingChildren = lists:keydelete(Id, #child.id, State1#state.children),
414+
% TODO: log supervisor shutdown
335415
{stop, shutdown, State1#state{children = RemainingChildren}}
336416
end
337417
end;
338418
handle_info({restart_many_children, [#child{pid = undefined} = _Child | Children]}, State) ->
339419
{noreply, State, {timeout, 0, {restart_many_children, Children}}};
340420
handle_info(_Msg, State) ->
341-
%TODO: log unexpected message
421+
%TODO: log unexpected message to debug
342422
{noreply, State}.
343423

344424
%% @hidden
@@ -375,6 +455,7 @@ handle_child_exit(Pid, Reason, State) ->
375455
RemainingChildren = lists:keydelete(
376456
Pid, #child.pid, State1#state.children
377457
),
458+
% TODO: log supervisor shutdown
378459
{stop, shutdown, State1#state{children = RemainingChildren}}
379460
end;
380461
false ->

0 commit comments

Comments
 (0)