[Erlang 0036] "HOW TO"不创建崩溃报告主动销毁gen_server进程

简介:
 昨天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.
复制代码

还没有结束

     这个问题比较简单,但是思考解决方案的过程还是做一下调整的,可能是更直接:
  1. 首先我们的目标是不想生成崩溃报告Crash Report,那崩溃报告是谁产生的呢?
  2. 这是一个gen_server进程,它创建使用的是proc_lib
  3. 而proc_lib创建的进程只有非正常退出的时候才会创建Crash Report,换句话说退出的原因不是normal或者shutdown
  4. 看一下gen_server对init回调函数的处理,哪一种退出是不exit(normal)
OK.
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
Linux Shell 网络安全
如何让Erlang服务器程序在后台运行,即实现守护进程的形态运行(★firecat推荐★)
如何让Erlang服务器程序在后台运行,即实现守护进程的形态运行(★firecat推荐★)
342 0
|
API
Erlang——直不断spawn新进程会有什么现象
前言 最近和同事聊天的时候,我突然想到进程Pid格式为,其中A1代表Node值, A2, A3则代表指定Node下的进程值,开始A3为0。当A2的值增加到一定数后, A3的值加1,那么问题来了: 1.
1315 0
|
Shell Perl 机器学习/深度学习
|
Web App开发
erlang的进程池。
转自: http://blog.sina.com.cn/s/blog_96b8a1540101542m.html   主要组成部分: https://github.com/devinus/poolboy https://github.
725 0
erlang 查看进程相关信息
出自: http://blog.sina.com.cn/s/blog_96b8a1540100zczz.html
734 0
|
网络协议
Erlang TCP Socket的接收进程的2种方案
转自:http://blog.csdn.net/summerhust/article/details/8740973   一旦打开了一个使用TCP连接的套接字,它就始终保持打开状态,直至任何一方关闭它或因为一个错误而终止。
1370 0
|
5月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
5月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
192 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)