Por que meu aplicativo Erlang está travando?
Pergunta
Estou construindo um aplicativo erlang simples e muito novo no ambiente, por isso estou tendo problemas para entender alguns erros que estou recebendo.Não tenho certeza de qual é a raiz do meu problema aqui, então se houver algo relevante que eu não poste, por favor me avise:
Fonte do módulo que estou executando:
-module(basilisk_server).
-author("Oak").
-export([start_link/2,start/0,start/1,start/2, stop/1]).
-behaviour(application).
-record(options,{
port = 6890,
server_opts = []
}).
-define(LocalIP,"192.168.64.128").
start()->
start([]).
start(Args)->
#options{port = Port, server_opts = ServerOpts} = parse_args(Args),
spawn(
fun() ->
start_link(Port, ServerOpts),
receive after infinity -> ok end
end)
.
start(_StartType, Args) ->
start(Args).
parse_args(Args) -> parse_args(Args, #options{}).
parse_args([], Opts) -> Opts;
parse_args([Head | Rest], Opts) ->
NewOpts =
case catch list_to_integer(Head) of
Port when is_integer(Port) ->
Opts#options{port = Port};
_Else ->
case Head of
"framed" ->
Opts#options{server_opts = [{framed, true} | Opts#options.server_opts]};
"" ->
Opts;
_Else ->
erlang:error({bad_arg, Head})
end
end,
parse_args(Rest, NewOpts)
.
stop(_State) ->
ok.
start_link(Port, ServerOpts) ->
io:format("Starting server on port ~p with args: ~p~n",[Port,ServerOpts]),
Services =
[
{"AuthenticationService",authenticationService_thrift},
{"UserRegistrationService",userRegistrationService_thrift}
]
,
{ok, _} = thrift_socket_server:start([
{ip, ?LocalIP},
{port, Port},
{name, ?MODULE},
{service, Services},
{handler,[
{"error_handler", thrift_error_handler},
{"AuthenticationService",authentication_service},
{"UserRegistrationService",user_registration_service}
]},
{socket_opts, [{recv_timeout, infinity}]}
]++
ServerOpts).
eu corro application:start(basilisk_server).
e receba essas mensagens nesta ordem:
{error,{bad_return,{{basilisk_server,start,[normal,[]]},
<0.38.0>}}}
=INFO REPORT==== 29-Jul-2014::03:11:06 ===
application: basilisk_server
exited: {bad_return,{{basilisk_server,start,[normal,[]]},<0.38.0>}}
type: temporary
=ERROR REPORT==== 29-Jul-2014::03:11:06 ===
Error in process <0.38.0> with exit value: {terminated,[{io,format,
[<0.36.0>,"Starting server on port ~p with args: ~p~n",[6890,[]]],[]},
{basilisk_server,start_link,2,[{file,"src/basilisk_server.erl"},{line,55}]},
{basilisk_server,'-start/1-fun-0-',2,[{file,"src/basilisk_serve...
O principal problema que estou tendo é identificar a origem real do erro.Fiquei com a impressão de que io:format
foi o problema por um curto período, mas acredito que foi uma "pista falsa" e que bad_result é a raiz do meu problema.Executei o programa em um estado quase idêntico e ele estava funcionando, e de repente comecei a receber esse erro.Reverti a maioria das alterações e isso não parou.Também tentei reiniciar, caso houvesse um problema com um processo em segundo plano.
Solução
Você está usando application:start
, que espera que seu módulo siga o application
comportamento.
Aquilo é:ele vai ligar foo:start/2
, para informar que seu aplicativo está sendo iniciado.Espera-se que você retorne {ok, Pid}
.Isso está documentado em "Aplicativos" capítulo dos Princípios de Design OTP.
No entanto, seu start
função chama imediatamente spawn
, e usa o resultado disso.Desde spawn
retorna Pid
, em vez de {ok, Pid}
, application:start
está reclamando de um descompasso no resultado esperado.
É por isso que você está vendo bad_return
:
{error,{bad_return,{{basilisk_server,start,[normal,[]]},
<0.38.0>}}}
Isso está lhe dizendo que você tem um error
, do tipo bad_return
.Aconteceu ao ligar basilisk_server:start(normal, [])
, e obteve um valor de retorno de <0.38.0>
(um pid).
Ah, e o outro erro é porque você usou start_link
, o que significa que seus dois processos estão vinculados.Quando um morrer, o outro será morto.Isto é o que você está vendo com o terminated
.Neste caso, aconteceu de ser morto no meio de io:format
;pode avançar ainda mais antes de ser morto em outras corridas.
Além disso, presume-se que um aplicativo inicie um supervisor raiz (é para isso que serve o pid retornado).
Neste ponto, você não precisa do application
comportamento.Na verdade, não estou convencido de que você precise da maior parte do seu código.Apenas ligue thrift_socket_server:start
e acabar com isso.Ele continuará sendo executado em segundo plano.