[Erlang 0036] "how to" does not create a crash report to actively destroy gen_server Processes

Source: Internet
Author: User
Yesterday, SC encountered a problem. When creating a gen_server, it checked whether the dependent external service is available in the init method. If it is unavailable, it directly returned {stop, reason }, the gen_server process fails to be created. This target is easily achieved, but the crash report is created after the process fails to be started. This exception is predictable and does not require the creation of a crash report; why does the crash report generate? How can this problem be eliminated? The init code is basically like this:
init([]) ->
process_flag(trap_exit, true),
case is_service_available() of
{ok, Sock} ->
{ok, #tcp_connector_state{sock = Sock}};
{error, Reason} ->
?Error("service not available:~p~n", [Reason]),
{stop,Reason}
end.
First of all to confirm is gen_server on the init callback function return value Specification Description, the official documentation link: http://www.erlang.org/doc/man/gen_server.html
Module:init(Args) -> Result
Types:
Args = term()
Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate}
| {stop,Reason} | ignore
State = term()
Timeout = int()>=0 | infinity
Reason = term()
The following explanation also states that {stop, reason} should be returned if an error occurs during startup }:
If something goes wrong during the initialization the function shocould return {stop, reason} Where reason is any term, or ignore.
Check the annotation of gen_server on start_link/start:
If module: init/1 fails with reason, the function returns {error, reason }. if module: init/1 returns {stop, reason} or ignore, the process is terminated and the function returns {error, reason} or ignore, respectively.
It seems that there is no problem. The most direct method below is to look at how gen_server code processes the various return values of init:
%%% ---------------------------------------------------
%%% Initiate the new process.
%%% Register the name using the Rfunc function
%%% Calls the Mod:init/Args function.
%%% Finally an acknowledge is sent to Parent and the main
%%% loop is entered.
%%% ---------------------------------------------------
init_it(Starter, self, Name, Mod, Args, Options) ->
init_it(Starter, self(), Name, Mod, Args, Options);
init_it(Starter, Parent, Name0, Mod, Args, Options) ->
Name = name(Name0),
Debug = debug_options(Name, Options),
case catch Mod:init(Args) of
{ok, State} ->
proc_lib:init_ack(Starter, {ok, self()}),
loop(Parent, Name, State, Mod, infinity, Debug);
{ok, State, Timeout} ->
proc_lib:init_ack(Starter, {ok, self()}),
loop(Parent, Name, State, Mod, Timeout, Debug);
{stop, Reason} ->
%% For consistency, we must make sure that the
%% registered name (if any) is unregistered before
%% the parent process is notified about the failure.
%% (Otherwise, the parent process could get
%% an 'already_started' error if it immediately
%% tried starting the process again.)
unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
ignore ->
unregister_name(Name0),
proc_lib:init_ack(Starter, ignore),
exit(normal);
{'EXIT', Reason} ->
unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
Else ->
Error = {bad_return_value, Else},
proc_lib:init_ack(Starter, {error, Error}),
exit(Error)
end.
Everything is clear here. When mod: Init (ARGs) returns {stop, reason}, the last step is to exit (reason) after cleaning ); what if I quit? Note that gen_server creates a process using proc_lib. The reason why the process created using proc_lib exits is neither normal nor shutdown. A process crash report is created, this will write the default SASL event handler. The error report will be visible only when SASL is started. this is mentioned in the previous article [Erlang 0017] Erlang/OTP Basic module proc_lib. proc_lib official documentation: http://www.erlang.org/doc/man/proc_lib.html reasons to know, the solution is very obvious, from the code above we can see that when mod: init return value is ignore when the processing method is exit (normal ); the crash report will not be created when the process exits like this. Do this:
init([]) ->
process_flag(trap_exit, true),
case is_service_available() of
{ok, Sock} ->
{ok, #tcp_connector_state{sock = Sock}};
{error, Reason} ->
?Error("service not available:~p~n", [Reason]),
ignore
end.
It is relatively simple to end the problem, but the process of thinking about the solution is still adjusted, which may be more direct:
  1. First, our goal is not to generate a crash report. who generated the crash report?
  2. This is a gen_server process, which is created using proc_lib
  3. The crash report is created only when the process created by proc_lib exits abnormally. In other words, the reason for exit is not normal or shutdown.
  4. Let's take a look at how gen_server processes the init callback function. Which exit function does not exit (normal)
OK.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.