You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨节点调用Erlang gen_server时出现noproc错误求助

Erlang跨节点调用gen_server出现noproc错误

问题场景

同一机器上运行两个Erlang节点,共享cookie,双向net_adm:ping/1连通正常。back@<ip>节点上的gen_server通过rebar3的supervisor启动无报错,front@<ip>节点用global:registered_names/0能看到注册名back_server。但调用erpc:call('back@<ip>', back_server, getState, [])时,虽然能打印出getState called,却抛出错误:

** exception exit: {exception,{noproc,{gen_server,call,[back_server,get]}}}

问题代码

-module(back_server).
-behaviour(gen_server).

-export([start/0,start/3,stop/0,setState/1,getState/0]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).

start() ->
    gen_server:start_link({global, ?MODULE}, ?MODULE, [], []).
start(Registration_type,Name,Args) ->
    gen_server:start_link({Registration_type, Name}, ?MODULE, Args, []).
stop() -> gen_server:call(?MODULE, stop).

setState(NewState)->
        io:format("setState called~n"),
        gen_server:cast(?MODULE,{update,NewState}).

getState()->
        io:format("getState called~n"),
        gen_server:call(?MODULE,get).
init([]) ->
        {ok,started}.
handle_call(get, _From, State) ->
        {reply,State,State};
handle_call(stop, _From, _State) ->
        {stop,normal,
                stopped,
          down}.

handle_cast({update,Value}, State) ->
        io:format("changing state from ~p to ~p~n",[State,Value]),
        {noreply,Value};
handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(_Info, State) ->
    {noreply, State}.
terminate(_Reason, _State) ->
    ok.
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

原因分析与解决方法

问题核心是:你的gen_server用全局注册方式启动({global, ?MODULE}),但getState/0、setState/1、stop/0这些函数内部调用gen_server时,用的是本地注册名?MODULE。

当erpc:call远程触发back_server:getState()时,这个函数在back@<ip>节点执行,此时gen_server:call(?MODULE, get)会去本地进程注册表找back_server,但你的进程只注册在全局表里,本地表没有对应记录,所以报错noproc(找不到进程)。

只需要把这些函数里的调用目标改成全局注册的格式即可:

修改后的关键代码片段:

stop() -> gen_server:call({global, ?MODULE}, stop).

setState(NewState)->
        io:format("setState called~n"),
        gen_server:cast({global, ?MODULE},{update,NewState}).

getState()->
        io:format("getState called~n"),
        gen_server:call({global, ?MODULE},get).

这样,函数执行时会正确通过全局注册表找到对应的gen_server进程,就不会再报找不到进程的错误了。

补充说明:既然global:registered_names/0能看到back_server,说明supervisor启动gen_server时确实用了全局注册(不管是调用start/0还是start/3传了global类型),这部分没问题,无需修改启动逻辑。

内容的提问来源于stack exchange,提问作者Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:43:21