gpt4 book ai didi

linux - Erlang,process_flag trap_exit 从 CLI 杀死了我的 gen_server

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:25:10 25 4
gpt4 key购买 nike

我有一个正在使用的 gen_server:

-module(user_info_provider).
-export([start_link/0, stop/0]).
-export([init/1, terminate/2, handle_info/2, handle_call/3, handle_cast/2,
code_change/3]).
-export([request_user_info/2]).

-behaviour(gen_server).

start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

stop() ->
gen_server:cast(?MODULE, stop).

request_user_info(From,UserId) ->
gen_server:cast(?MODULE, {request_user_info, From, UserId}).
%% Callback Functions
init(_) ->
process_flag(trap_exit, true),
io:format("I am ~w ~n", [self()]),
{ok, null}.
%% @doc terminate
terminate(Reason, _LoopData) ->
io:format("Terminating by ~w~n",[Reason]),
{ok, null}.
handle_cast({request_user_info,From,UserId}, LoopData) ->
{noreply, LoopData};
handle_cast(stop, LoopData) ->
{stop, normal, LoopData}.
handle_info(_Info, State) ->
{ok, State}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
handle_call(_,_From,LoopData) ->
{ok,ok,LoopData}.

问题是,正如我接下来展示的那样,如果我从 cli 中执行它,如 erl -pa ebin/-s user_info_provider start_link 它会立即消失,但我可以从控制台生成它并且有效。

erl -pa ebin -s user_info_provider start_link
Erlang R14B02 (erts-5.8.3) [source] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]

I am <0.32.0>
Terminating by normal
Eshell V5.8.3 (abort with ^G)
1> user_info_provider:start_link().
I am <0.35.0>
{ok,<0.35.0>}

如果我不设置 process_flag(trap_exit, true) 或者我不使用 -s 模块函数直接从控制台启动它,这不会发生.
我这样启动它是因为真正的 gen_server 更复杂,我正在通过 Makefile 调用独立测试它。
有什么想法吗?

最佳答案

解决方案是 W55tKQbuRu28Q4xv 建议的解决方案,或者不使用 start_link,仅使用 start。这是发生的事情:

-s参数由init处理。粗略地说,init 将生成 一个新进程,然后使用该进程初始化并运行其中的所有-s 参数。之后,这个生成的进程将退出。

由于 init-process 退出,并且您陷阱退出,您的进程收到一条消息 {'EXIT', P, Reason} 其中 P 是 pid() spawned-by-init 进程。此消息由进程的 gen_server 部分处理。通常这样的消息会被转发到你的 handle_info/2 回调(顺便说一下,它在你的代码中有错误的返回值,应该是 noreply)。但在这种情况下,它不会被转发。原因是 gen_server 包含其 parent 进程的概念。它通过进程字典和由 proc_lib 放置的值 '$ancestors' 记录了哪个进程产生了它。现在,如果退出消息从 parent 到达,则立即调用终止回调并终止进程。此类消息不会转发给您。这就是您所看到的。

解决方案,漂亮的解决方案,是创建一个小应用程序,一个主管,并将您的流程置于该主管之下。然后从 -s 调用 application:start(your_app)。这样做的原因是因为应用程序 Controller 单独运行。更好的解决方案是构建一个将自动启动您的应用程序的版本。发布是您的应用程序 + 其依赖项与 ERTS 运行时捆绑在一起。这样的版本完全独立存在,可以复制到目标主机并运行。因此,目标系统上不需要 Erlang,因为该版本是自包含的。

关于linux - Erlang,process_flag trap_exit 从 CLI 杀死了我的 gen_server,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7743789/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com