Erlang:OTP - 正确传递 children 个参数;工人异常退出
Erlang: OTP - properly passing children arguments; workers exiting with exceptions
我有一个主管/工人树组织如下:
game_super -> {keyserver: worker, loginserver: super}
loginserver -> loginlistener: worker (socket pool)
密钥服务器工作正常。它只是 returns 它用来构造登录令牌的随机字节串。它会定期更换。
我的登录服务器用于在 R16 下工作。后来升级到R18因为想用地图。 IDK 如果那是问题所在……不过我对此表示怀疑。我做的另一个改变是我需要地图的原因是为了方便设置 children.
我有多个redis服务器,每个都有自己的用途。一是速率限制。这是目前唯一在运营的一家。我在 game_supervisor:init([])
中调用 game_core:redis_init()
。它returns{ok,{#MapPids, #MapScriptKeys}
。其中 #MapScriptKeys
值是包含 LUA 脚本的所有 Sha 哈希值的元组。
我得到 exception exit: {shutdown,{failed_to_start_child,login,<0.178.0>}}
Pid 明显改变,但这是调用 game_supervisor:start_inshell()
后的最后结果。
我在 login_listener:init(State)
中的 {ok, State}
之前插入了一个 io:format("~p\n",[State]),
,它会打印出所有内容……一次。考虑到那是在返回之前....它怎么会失败?
代码基于:http://learnyousomeerlang.com/buckets-of-sockets
这是否类似于:Erlang supervisor exception on starting worker,children 重复使用相同的名称?
游戏监督
-module(game_supervisor).
-behavior(supervisor).
-include("constants.hrl").
-export([start/0, start/1, start_inshell/0, init/1]).
start(Args) ->
spawn(fun() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args)
end).
start_inshell() ->
{ok, Pid} = supervisor:start_link({local, ?MODULE}, ?MODULE, []),
unlink(Pid).
start() -> start([]).
init([]) ->
{ok, RedisState} = game_core:redis_init(),
{ok, {
{one_for_one, 2, 10}, [ %more than 2 restarts w/i 10 seconds all killed
{key,
{key_server, start_link, []},
permanent,
10000,
worker,
[key_server]},
{login,
{login_server, start_link, [RedisState]},
permanent,
10000,
supervisor,
[login_server]}%,
% {game,
% {game_server, start_link, [RedisState]},
% permanent,
% 10000,
% supervisor,
% [game_server]}
]}}.
登录服务器
-module(login_server).
-behavior(supervisor).
-include("constants.hrl").
-export([start_link/0, start_link/1, init/1, start_socket/0]).
start_link(Args) ->
spawn(fun() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args)
end).
start_link() -> start_link([]).
init({Pid,Scripts}) ->
process_flag(trap_exit, true),
{ok, Socket} = gen_tcp:listen(?PORT_LISTEN_LOGIN, [{active,once}, {reuseaddr, true}]),
%Construct socket pool
spawn_link(fun start_pool/0),
%Put all redis information for login clients here
RedisState = {maps:get(limiter,Pid),maps:get(limiter,Scripts)},
%Child specification
{ok, {
{simple_one_for_one, 2, 10}, [ %more than 2 restarts w/i 10 seconds all killed
{listener,
{login_listener, start_link, [{Socket, RedisState}]},
temporary,
1000,
worker,
[login_listener]}
]}}.
start_pool() ->
[start_socket() || _ <- lists:seq(1,32)],
ok.
start_socket() -> supervisor:start_child(?MODULE, []).
登录处理程序
-module(login_listener).
-behavior(gen_server).
-include("constants.hrl").
-export([start_link/1]).
%required callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start_link(State) ->
gen_server:start_link(?MODULE, State,[]).
init(State) ->
process_flag(trap_exit, true),
gen_server:cast(self(), accept),
{ok, State}.
handle_cast(accept, State) -> %Param(s): Msg, State
{Socket, RedisState} = State,
{ok, AcceptSocket} = gen_tcp:accept(Socket),
login_server:start_socket(),
{noreply, {AcceptSocket, RedisState}}.
handle_info({tcp, Socket, Str}, State) -> %Param(s): Info
%%Login
{_, {PidLimiter,{ShaLimiter}}} = State,
{ok, {ClientIP, _ }} = inet:peername(Socket),
{ok, Result} = game_core:rate_limit(PidLimiter, ShaLimiter, ClientIP),
ok = inet:setopts(Socket, [{active, once}]),
{noreply, State}.
%%Surpress warnings
handle_call(_, _, State) -> {noreply, State}. %Param(s): Request, From
terminate(_, _) -> ok. %Param(s): Reason, State
code_change(_, State,_) -> {ok, State}. %Param(s): OldVsn, Extra
为什么你的主管启动函数调用 spawn/1
?对于 game_supervisor
,更改为:
start(Args) ->
spawn(fun() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args)
end).
对此:
start(Args) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args).
对于 login_server
,更改为:
start_link(Args) ->
spawn(fun() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args)
end).
对此:
start_link(Args) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args).
我有一个主管/工人树组织如下:
game_super -> {keyserver: worker, loginserver: super}
loginserver -> loginlistener: worker (socket pool)
密钥服务器工作正常。它只是 returns 它用来构造登录令牌的随机字节串。它会定期更换。
我的登录服务器用于在 R16 下工作。后来升级到R18因为想用地图。 IDK 如果那是问题所在……不过我对此表示怀疑。我做的另一个改变是我需要地图的原因是为了方便设置 children.
我有多个redis服务器,每个都有自己的用途。一是速率限制。这是目前唯一在运营的一家。我在 game_supervisor:init([])
中调用 game_core:redis_init()
。它returns{ok,{#MapPids, #MapScriptKeys}
。其中 #MapScriptKeys
值是包含 LUA 脚本的所有 Sha 哈希值的元组。
我得到 exception exit: {shutdown,{failed_to_start_child,login,<0.178.0>}}
Pid 明显改变,但这是调用 game_supervisor:start_inshell()
后的最后结果。
我在 login_listener:init(State)
中的 {ok, State}
之前插入了一个 io:format("~p\n",[State]),
,它会打印出所有内容……一次。考虑到那是在返回之前....它怎么会失败?
代码基于:http://learnyousomeerlang.com/buckets-of-sockets
这是否类似于:Erlang supervisor exception on starting worker,children 重复使用相同的名称?
游戏监督
-module(game_supervisor).
-behavior(supervisor).
-include("constants.hrl").
-export([start/0, start/1, start_inshell/0, init/1]).
start(Args) ->
spawn(fun() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args)
end).
start_inshell() ->
{ok, Pid} = supervisor:start_link({local, ?MODULE}, ?MODULE, []),
unlink(Pid).
start() -> start([]).
init([]) ->
{ok, RedisState} = game_core:redis_init(),
{ok, {
{one_for_one, 2, 10}, [ %more than 2 restarts w/i 10 seconds all killed
{key,
{key_server, start_link, []},
permanent,
10000,
worker,
[key_server]},
{login,
{login_server, start_link, [RedisState]},
permanent,
10000,
supervisor,
[login_server]}%,
% {game,
% {game_server, start_link, [RedisState]},
% permanent,
% 10000,
% supervisor,
% [game_server]}
]}}.
登录服务器
-module(login_server).
-behavior(supervisor).
-include("constants.hrl").
-export([start_link/0, start_link/1, init/1, start_socket/0]).
start_link(Args) ->
spawn(fun() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args)
end).
start_link() -> start_link([]).
init({Pid,Scripts}) ->
process_flag(trap_exit, true),
{ok, Socket} = gen_tcp:listen(?PORT_LISTEN_LOGIN, [{active,once}, {reuseaddr, true}]),
%Construct socket pool
spawn_link(fun start_pool/0),
%Put all redis information for login clients here
RedisState = {maps:get(limiter,Pid),maps:get(limiter,Scripts)},
%Child specification
{ok, {
{simple_one_for_one, 2, 10}, [ %more than 2 restarts w/i 10 seconds all killed
{listener,
{login_listener, start_link, [{Socket, RedisState}]},
temporary,
1000,
worker,
[login_listener]}
]}}.
start_pool() ->
[start_socket() || _ <- lists:seq(1,32)],
ok.
start_socket() -> supervisor:start_child(?MODULE, []).
登录处理程序
-module(login_listener).
-behavior(gen_server).
-include("constants.hrl").
-export([start_link/1]).
%required callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start_link(State) ->
gen_server:start_link(?MODULE, State,[]).
init(State) ->
process_flag(trap_exit, true),
gen_server:cast(self(), accept),
{ok, State}.
handle_cast(accept, State) -> %Param(s): Msg, State
{Socket, RedisState} = State,
{ok, AcceptSocket} = gen_tcp:accept(Socket),
login_server:start_socket(),
{noreply, {AcceptSocket, RedisState}}.
handle_info({tcp, Socket, Str}, State) -> %Param(s): Info
%%Login
{_, {PidLimiter,{ShaLimiter}}} = State,
{ok, {ClientIP, _ }} = inet:peername(Socket),
{ok, Result} = game_core:rate_limit(PidLimiter, ShaLimiter, ClientIP),
ok = inet:setopts(Socket, [{active, once}]),
{noreply, State}.
%%Surpress warnings
handle_call(_, _, State) -> {noreply, State}. %Param(s): Request, From
terminate(_, _) -> ok. %Param(s): Reason, State
code_change(_, State,_) -> {ok, State}. %Param(s): OldVsn, Extra
为什么你的主管启动函数调用 spawn/1
?对于 game_supervisor
,更改为:
start(Args) ->
spawn(fun() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args)
end).
对此:
start(Args) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args).
对于 login_server
,更改为:
start_link(Args) ->
spawn(fun() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args)
end).
对此:
start_link(Args) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, Args).