[Erlang 0036] "HOW TO"不创建崩溃报告主动销毁gen_server进程
来源:互联网 发布:汽车数据发动机数据 编辑:程序博客网 时间:2024/05/01 02:50
昨天SC遇到一个问题,创建一个gen_server的时候会在init方法中检查依赖的外部服务是否可用;如果不可用的话他就直接返回{stop,Reason},gen_server进程创建失败;这个目标他很容易就达到了,但是进程启动失败之后却创建了Crash Report,这种异常情况是可以预料的并不需要创建崩溃报告Crash Report;为什么会产生崩溃报告Crash Report?如何消除呢?他的init代码大体上是这样的:
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.
首先要确认的是gen_server对init回调函数的返回值规格说明, 官方文档链接: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()
并且下面的解释也说了如果启动中遇到错误应该返回{stop,Reason}:
If something goes wrong during the initialization the function should return {stop,Reason} where Reason is any term, or ignore.
同时查看gen_server对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.
貌似也没有什么问题,下面最直接的方法就是去看看gen_server代码对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.
看到这里一切都明朗了,当Mod:init(Args)返回值是 {stop, Reason} 的时候在完成清理工作之后最后一步做了exit(Reason);这样退出又会怎样呢?注意gen_server创建进程是使用proc_lib创建的,而使用proc_lib创建的进程退出的原因不是normal也不是shutdown的时候,就会创建一个进程崩溃报告,这个会写入默认的SASL的事件handler,错误报告会在只有在启动了SASL的时候才能看到.这个在之前的文章中[Erlang 0017]Erlang/OTP基础模块 proc_lib 中我们已经提到提到过. proc_lib的官方文档:http://www.erlang.org/doc/man/proc_lib.html
原因知道了,解决方法也就很显然了,从上面的代码中可以看到当Mod:init返回值是ignore的时候处理方式是exit(normal);而进程这样退出是不会创建Crash Report的,搞定:
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.
还没有结束
这个问题比较简单,但是思考解决方案的过程还是做一下调整的,可能是更直接:
- 首先我们的目标是不想生成崩溃报告Crash Report,那崩溃报告是谁产生的呢?
- 这是一个gen_server进程,它创建使用的是proc_lib
- 而proc_lib创建的进程只有非正常退出的时候才会创建Crash Report,换句话说退出的原因不是normal或者shutdown
- 看一下gen_server对init回调函数的处理,哪一种退出是不exit(normal)
OK.
- [Erlang 0036] "HOW TO"不创建崩溃报告主动销毁gen_server进程
- How to Solve "Latch- cache buffers chains"
- " " ' '
- Erlang gen_server进程调用实例
- Don't know how to iterate over supplied "items" in <forEach>解决办法
- String s = "a" + "b" + "c" + "d" + "
- SharePoint"在数据表中编辑"不可用
- 远离"不聪明且勤奋的人"
- Don't Hesitate to say "no"
- Unable to resolve resource bundle for locale "en_US"
- 解决ClusterwarePRCT-1011:Failed to run "oifcfg".Det...
- "Fail to create SQL Server Certificate" during installation
- 显示Syntax error, insert ";" to complete Statement
- 有谁知道Delphi中"窗口"的创建过程?
- about"spaceused"
- extern "c"
- 说好"but"
- Erlang - gen_server
- [Erlang 0031] Erlang Shell中的输出完整数据
- [Erlang 0032] Erlang Binary的内部实现
- [Erlang 0033] 接入Erlang控制台的几种方法
- [Erlang 0034] Erlang iolist
- [Erlang 0035] Erlang SMP
- [Erlang 0036] "HOW TO"不创建崩溃报告主动销毁gen_server进程
- [Erlang 0037] Erlang Parameterized Module
- [Erlang 0038] Node.js & Erlang
- [Erlang 0039] Erlang Inheritance
- [Erlang 0040] Hidden Features of Erlang
- [Erlang 0041] 详解io:format
- [Erlang 0042] Erlang 动态执行
- [Erlang 0043] Erlang Code Snippet
- [Erlang 0044] Erlang Shell History