我正在尝试实现一个简单的主管,只要它们失败就重启子进程。但是,我甚至不知道如何在主管下产生多个进程!我在这个网站上查看了简单的管理员代码并找到了一些东西
-module(echo_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() ->
{ok, Pid} = supervisor:start_link(echo_sup, []),
unlink(Pid).
init(_Args) ->
{ok, {{one_for_one, 5, 60},
[{echo_server, {echo_server, start_link, []},
permanent, brutal_kill, worker, [echo_server]},
{echo_server2, {echo_server2, start_link, []},
permanent, brutal_kill, worker, [echo_server2]}]}}.
我假设将“echo_server2”部分放在init()函数中会在该supervisor下生成另一个进程,但我最终得到一个异常退出:shutdown message。
文件“echo_server”和“echo_server2”都是相同的代码,但名称不同。所以我现在很困惑。
-module(echo_server2).
-behaviour(gen_server).
-export([start_link/0]).
-export([echo/1, crash/0]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link() ->
{ok,Pid} = gen_server:start_link({local, echo_server2}, echo_server2, [], []),
unlink(Pid).
%% public api
echo(Text) ->
gen_server:call(echo_server2, {echo, Text}).
crash() ->
gen_server:call(echo_server2, crash).
%% behaviours
init(_Args) ->
{ok, none}.
handle_call(crash, _From, State) ->
X=1,
{reply, X=2, State};
handle_call({echo, Text}, _From, State) ->
{reply, Text, State}.
handle_cast(_, State) ->
{noreply, State}.
答案 0 :(得分:4)
首先,您需要阅读有关OTP / gen_server和OTP /主管的一些文档。您的代码中几乎没有错误。
1)在echo_sup模块中更改start_link函数,如下所示:
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
不知道你为什么在进程开始后unlink/1
。
2)在echo_servers中,将start_link函数更改为:
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
您不应该更改此函数的返回值,因为主管期望其中一个值:
{ok,Pid} | ignore | {error,Error}
答案 1 :(得分:2)
您不需要两个不同的模块来运行同一服务器的两个实例。冲突问题是由于子规范中的标记必须是唯一的。它是元组中的第一个元素。所以你可以有类似的东西:
[{echo_server, {echo_server, start_link, []},
permanent, brutal_kill, worker, [echo_server]},
{echo_server2, {echo_server, start_link, []},
permanent, brutal_kill, worker, [echo_server]}]}}.
为什么要取消子进程的链接?主管使用这些链接来监督其子女。你得到的错误是主管期望启动子节点的函数返回{ok,ChildPid}
,这就是它获取子节点的pid的方式,所以当它获得另一个返回值时,它将无法启动子节点和然后放弃自己。一切都根据它应该如何工作。
如果要注册两个服务器,则可以修改start_link
函数以将该名称用作参数并传递,以便您可以通过子规范明确传递它。所以:
start_link(Name) ->
gen_server:start_link({local, Name}, ?MODULE, [], []).
和
[{echo_server, {echo_server, start_link, [echo_server]},
permanent, brutal_kill, worker, [echo_server]},
{echo_server2, {echo_server, start_link, [echo_server2]},
permanent, brutal_kill, worker, [echo_server]}]}}.
使用模块名称作为服务器的注册名称只是一种惯例,只有在运行服务器的一个实例时才有效。