Current section
Files
Jump to
Current section
Files
src/gleam@otp@supervisor.erl
-module(gleam@otp@supervisor).
-compile(no_auto_import).
-export([add/2, supervisor/1, worker/1, returning/2, start_spec/1, start/1, application_stopped/0, to_erlang_start_result/1, from_erlang_start_result/1, wrap_erlang_starter/1]).
-export_type([spec/2, children/1, child_spec/3, child_start_error/0, message/0, instruction/0, state/1, starter/1, child/1, handle_exit_error/0, application_start_mode/0, application_stop/0]).
-type spec(FEQ, FER) :: {spec,
FEQ,
integer(),
integer(),
fun((children(FEQ)) -> children(FER))}.
-opaque children(FES) :: {ready, starter(FES)} | {failed, child_start_error()}.
-opaque child_spec(FET, FEU, FEV) :: {child_spec,
fun((FEU) -> {ok,
gleam@otp@process:sender(FET)} |
{error, gleam@otp@actor:start_error()}),
fun((FEU, gleam@otp@process:sender(FET)) -> FEV)}.
-type child_start_error() :: {child_start_error,
gleam@option:option(gleam@otp@process:pid_()),
gleam@otp@actor:start_error()}.
-opaque message() :: {exit, gleam@otp@process:exit()} |
{retry_restart, gleam@otp@process:pid_()}.
-type instruction() :: start_all | {start_from, gleam@otp@process:pid_()}.
-type state(FEW) :: {state,
gleam@otp@intensity_tracker:intensity_tracker(),
starter(FEW),
gleam@otp@process:sender(gleam@otp@process:pid_())}.
-type starter(FEX) :: {starter,
FEX,
gleam@option:option(fun((instruction()) -> {ok,
{starter(FEX),
instruction()}} |
{error, child_start_error()}))}.
-type child(FEY) :: {child, gleam@otp@process:pid_(), FEY}.
-type handle_exit_error() :: {restart_failed,
gleam@otp@process:pid_(),
gleam@otp@intensity_tracker:intensity_tracker()} |
too_many_restarts.
-type application_start_mode() :: normal |
{takeover, gleam@otp@node:node_()} |
{failover, gleam@otp@node:node_()}.
-type application_stop() :: any().
-spec start_child(child_spec(any(), FGB, FGC), FGB) -> {ok, child(FGC)} |
{error, child_start_error()}.
start_child(Child_spec, Argument) ->
case begin
_pipe = (erlang:element(2, Child_spec))(Argument),
gleam@result:map_error(
_pipe,
fun(_capture) -> {child_start_error, none, _capture} end
)
end of
{error, _try} -> {error, _try};
{ok, Channel} ->
{ok,
{child,
gleam@otp@process:pid(Channel),
(erlang:element(3, Child_spec))(Argument, Channel)}}
end.
-spec shutdown_child(gleam@otp@process:pid_(), child_spec(any(), any(), any())) -> nil.
shutdown_child(Pid, _) ->
gleam@otp@process:send_exit(Pid, normal).
-spec perform_instruction_for_child(
FGP,
instruction(),
child_spec(any(), FGP, FGR),
child(FGR)
) -> {ok, {child(FGR), instruction()}} | {error, child_start_error()}.
perform_instruction_for_child(Argument, Instruction, Child_spec, Child) ->
Current = erlang:element(2, Child),
case Instruction of
{start_from, Target} when Target =/= Current ->
{ok, {Child, Instruction}};
_@1 ->
shutdown_child(Current, Child_spec),
case start_child(Child_spec, Argument) of
{error, _try} -> {error, _try};
{ok, Child@1} ->
{ok, {Child@1, start_all}}
end
end.
-spec add_child_to_starter(
starter(FGZ),
child_spec(any(), FGZ, FHC),
child(FHC)
) -> starter(FHC).
add_child_to_starter(Starter, Child_spec, Child) ->
Starter@3 = fun(Instruction) -> case case erlang:element(3, Starter) of
{some, Start} ->
Start(Instruction);
none ->
{ok, {Starter, Instruction}}
end of
{error, _try} -> {error, _try};
{ok, {Starter@1, Instruction@1}} ->
case perform_instruction_for_child(
erlang:element(2, Starter@1),
Instruction@1,
Child_spec,
Child
) of
{error, _try@1} -> {error, _try@1};
{ok, {Child@1, Instruction@2}} ->
Starter@2 = add_child_to_starter(
Starter@1,
Child_spec,
Child@1
),
{ok, {Starter@2, Instruction@2}}
end
end end,
{starter, erlang:element(3, Child), {some, Starter@3}}.
-spec start_and_add_child(starter(FHI), child_spec(any(), FHI, FHL)) -> children(FHL).
start_and_add_child(State, Child_spec) ->
case start_child(Child_spec, erlang:element(2, State)) of
{ok, Child} ->
{ready, add_child_to_starter(State, Child_spec, Child)};
{error, Reason} ->
{failed, Reason}
end.
-spec add(children(FHQ), child_spec(any(), FHQ, FHT)) -> children(FHT).
add(Children, Child_spec) ->
case Children of
{failed, Fail} ->
{failed, Fail};
{ready, State} ->
start_and_add_child(State, Child_spec)
end.
-spec supervisor(
fun((FHY) -> {ok, gleam@otp@process:sender(FHZ)} |
{error, gleam@otp@actor:start_error()})
) -> child_spec(FHZ, FHY, FHY).
supervisor(Start) ->
{child_spec, Start, fun(Argument, _) -> Argument end}.
-spec worker(
fun((FIG) -> {ok, gleam@otp@process:sender(FIH)} |
{error, gleam@otp@actor:start_error()})
) -> child_spec(FIH, FIG, FIG).
worker(Start) ->
{child_spec, Start, fun(Argument, _) -> Argument end}.
-spec returning(
child_spec(FIO, FIP, any()),
fun((FIP, gleam@otp@process:sender(FIO)) -> FIV)
) -> child_spec(FIO, FIP, FIV).
returning(Child, Updater) ->
{child_spec, erlang:element(2, Child), Updater}.
-spec init(spec(any(), FJA)) -> gleam@otp@actor:init_result(state(FJA), message()).
init(Spec) ->
{Retry_sender, Retry_receiver} = gleam@otp@process:new_channel(),
Retry_receiver@1 = gleam@otp@process:map_receiver(
Retry_receiver,
fun(A) -> {retry_restart, A} end
),
Exit_receiver = begin
_pipe = gleam@otp@process:trap_exits(),
gleam@otp@process:map_receiver(_pipe, fun(A) -> {exit, A} end)
end,
Receiver = begin
_pipe@1 = Exit_receiver,
gleam@otp@process:merge_receiver(_pipe@1, Retry_receiver@1)
end,
Result = begin
_pipe@2 = {starter, erlang:element(2, Spec), none},
_pipe@3 = {ready, _pipe@2},
(erlang:element(5, Spec))(_pipe@3)
end,
case Result of
{ready, Starter} ->
Restarts = gleam@otp@intensity_tracker:new(
erlang:element(3, Spec),
erlang:element(4, Spec)
),
State = {state, Restarts, Starter, Retry_sender},
{ready, State, {some, Receiver}};
{failed, Reason} ->
Reason@1 = {abnormal, gleam@dynamic:from(Reason)},
{failed, Reason@1}
end.
-spec handle_exit(gleam@otp@process:pid_(), state(FJG)) -> gleam@otp@actor:next(state(FJG)).
handle_exit(Pid, State) ->
Outcome = begin
{some, Start@1} = case erlang:element(3, erlang:element(3, State)) of
{some, Start} -> {some, Start};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"gleam/otp/supervisor"/utf8>>,
function => <<"handle_exit"/utf8>>,
line => 289})
end,
case begin
_pipe = erlang:element(2, State),
_pipe@1 = gleam@otp@intensity_tracker:add_event(_pipe),
gleam@result:map_error(_pipe@1, fun(_) -> too_many_restarts end)
end of
{error, _try@1} -> {error, _try@1};
{ok, Restarts} ->
case begin
_pipe@2 = Start@1({start_from, Pid}),
gleam@result:map_error(
_pipe@2,
fun(E) ->
{restart_failed,
gleam@option:unwrap(erlang:element(2, E), Pid),
Restarts}
end
)
end of
{error, _try@2} -> {error, _try@2};
{ok, {Starter, _@1}} ->
{ok,
erlang:setelement(
2,
erlang:setelement(3, State, Starter),
Restarts
)}
end
end
end,
case Outcome of
{ok, State@1} ->
{continue, State@1};
{error, {restart_failed, Failed_child, Restarts@1}} ->
gleam@otp@process:send(erlang:element(4, State), Failed_child),
State@2 = erlang:setelement(2, State, Restarts@1),
{continue, State@2};
{error, too_many_restarts} ->
{stop, {abnormal, gleam@dynamic:from(too_many_restarts)}}
end.
-spec loop(message(), state(FJK)) -> gleam@otp@actor:next(state(FJK)).
loop(Message, State) ->
case Message of
{exit, {exit, Pid, _@1}} ->
handle_exit(Pid, State);
{retry_restart, Pid@1} ->
handle_exit(Pid@1, State)
end.
-spec start_spec(spec(any(), any())) -> {ok,
gleam@otp@process:sender(message())} |
{error, gleam@otp@actor:start_error()}.
start_spec(Spec) ->
gleam@otp@actor:start_spec(
{spec, fun() -> init(Spec) end, 60000, fun loop/2}
).
-spec start(fun((children(nil)) -> children(any()))) -> {ok,
gleam@otp@process:sender(message())} |
{error, gleam@otp@actor:start_error()}.
start(Init) ->
start_spec({spec, nil, 5, 1, Init}).
-spec application_stopped() -> application_stop().
application_stopped() ->
gleam_otp_external:application_stopped().
-spec to_erlang_start_result(
{ok, gleam@otp@process:sender(any())} |
{error, gleam@otp@actor:start_error()}
) -> {ok, gleam@otp@process:pid_()} | {error, gleam@dynamic:dynamic()}.
to_erlang_start_result(Res) ->
gleam@otp@actor:to_erlang_start_result(Res).
-spec from_erlang_start_result({ok, gleam@otp@process:pid_()} | {error, any()}) -> {ok,
gleam@otp@process:sender(any())} |
{error, gleam@otp@actor:start_error()}.
from_erlang_start_result(Start) ->
gleam@otp@actor:from_erlang_start_result(Start).
-spec wrap_erlang_starter(
fun(() -> {ok, gleam@otp@process:pid_()} | {error, any()})
) -> fun(() -> {ok, gleam@otp@process:sender(any())} |
{error, gleam@otp@actor:start_error()}).
wrap_erlang_starter(Start) ->
gleam@otp@actor:wrap_erlang_starter(Start).