Skip to content

Commit 51cdbc9

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 805230a commit 51cdbc9

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

@@ -111,30 +149,59 @@
111149
%% could be used to set a sane default for the platform (OTP uses 1000).
112150
-define(STALE_RESTART_LIMIT, 100).
113151

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

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

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

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

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

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

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

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

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

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

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

279+
-spec start_children(ChildSpecs :: [child_spec()], State :: #state{}) ->
280+
ChildSpecs :: [child_spec()].
209281
start_children([Child | T], StartedC) ->
210282
case try_start(Child) of
211283
{ok, Pid, _Result} ->
@@ -214,6 +286,7 @@ start_children([Child | T], StartedC) ->
214286
start_children([], StartedC) ->
215287
StartedC.
216288

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

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

368+
% @hidden
294369
handle_info({'EXIT', Pid, Reason}, State) ->
370+
% TODO: log crash report
295371
handle_child_exit(Pid, Reason, State);
296372
handle_info({ensure_killed, Pid}, State) ->
297373
case lists:keyfind(Pid, #child.pid, State#state.children) of
@@ -331,17 +407,19 @@ handle_info({try_again_restart, Id}, State) ->
331407
),
332408
{noreply, State1#state{children = UpdatedChildren}};
333409
{error, {_, _}} ->
410+
% TODO: log crash report
334411
{noreply, State1, {timeout, 0, {try_again_restart, Id}}}
335412
end;
336413
{shutdown, State1} ->
337414
RemainingChildren = lists:keydelete(Id, #child.id, State1#state.children),
415+
% TODO: log supervisor shutdown
338416
{stop, shutdown, State1#state{children = RemainingChildren}}
339417
end
340418
end;
341419
handle_info({restart_many_children, [#child{pid = undefined} = _Child | Children]}, State) ->
342420
{noreply, State, {timeout, 0, {restart_many_children, Children}}};
343421
handle_info(_Msg, State) ->
344-
%TODO: log unexpected message
422+
%TODO: log unexpected message to debug
345423
{noreply, State}.
346424

347425
%% @hidden
@@ -378,6 +456,7 @@ handle_child_exit(Pid, Reason, State) ->
378456
RemainingChildren = lists:keydelete(
379457
Pid, #child.pid, State1#state.children
380458
),
459+
% TODO: log supervisor shutdown
381460
{stop, shutdown, State1#state{children = RemainingChildren}}
382461
end;
383462
false ->

0 commit comments

Comments
 (0)