J'ai une erreur d'exécution dans la partie init d'un serveur_gen. - Init commence par process_flag (trap_exit, true) - gen_server fait partie d'un arbre de supervision J'essaie d'imprimer la raison dans le module de terminaison mais il semble sortir d'ailleurs. - pourquoi l'arrêt n'est pas appelé? L'application s'arrête avec l'arrêt comme raison. - Comment et où attraper l'erreur d'exécution?gen_server et les erreurs d'exécution
Répondre
Le rappel terminate
est normalement appelé dans cette situation, car vous avez des exits bloqués.
Le seul endroit où ce n'est pas le cas est si le crash se produit dans la fonction d'initialisation. Dans ce cas, la responsabilité incombe au superviseur, qui se résout habituellement en conséquence. Ensuite, cette erreur parcourt l'arborescence du superviseur jusqu'à ce qu'elle finisse par terminer votre application entière.
Généralement, le superviseur enregistre un rapport de superviseur avec le contexte défini sur start_error
. C'est votre indice que la partie de l'arbre de supervision a des problèmes que vous devriez gérer. Vous devriez vérifier ceci, parce que vous pouvez avoir la mauvaise supposition sur où l'erreur se produit.
REVISEE DE ICI
Votre problème est que vous ne savez pas du tout SASL. Étudie-le. Voici un exemple de comment l'utiliser.
Code Hissé de votre exemple:
D'abord, le bahlonga nécessaire pour dire Erlang, nous avons un gen_server.
-module(foo).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
Nous pirater le #state {} enregistrement de sorte qu'il peut être utilisé avec votre code
-record(state, { name, port, socket_listen }).
Basic start_linkage ...
start_link() ->
gen_server:start_link({local, foo}, ?MODULE, [], []).
Votre fonction init, problème de spawn inclus.
init([]) ->
Port = 3252,
Name = "foo",
Au-dessus, nous avons piraté un peu pour des raisons de simplification ...
process_flag(trap_exit, true),
erlang:error(blabla),
Opts = [binary, {reuseaddr, true},
{backlog,5}, {packet, 0}, {active, false}, {nodelay, true}],
case gen_tcp:listen(Port,Opts) of
{ok,Socket_Listen} ->
logger:fmsg("--> [~s,init] Socket_Listen crée = ~p",
[Name,Socket_Listen]),
{ok,handle_accept(#state{socket_listen=Socket_Listen})};
{error, Reason} ->
logger:fmsg("--> [~s,init] Erreur, Raison =~p",
[Name,Reason]), {stop, Reason}
end.
Hacks pour les fonctions manquantes ....
handle_accept(_) ->
#state{}.
Le reste est juste l'essentiel. .., donc je les omets.
maintenant pour foo_sup
le superviseur pour foo
:
-module(foo_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
-define(SERVER, ?MODULE).
lien de démarrage de base ...
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
Basic ChildSpec. Obtenez le foo enfant en marche ...
init([]) ->
FooCh = {foo, {foo, start_link, []},
permanent, 2000, worker, [foo]},
{ok, {{one_for_all,0,1}, [FooCh]}}.
Boot Erlang avec SASL activé:
[email protected]:~$ erl -boot start_sasl
Erlang R14B02 (erts-5.8.3) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
=PROGRESS REPORT==== 9-Dec-2010::01:01:51 ===
[..]
Eshell V5.8.3 (abort with ^G)
Essayons de nous frayer le superviseur ...
1> foo_sup:start_link().
Et nous obtenons ceci:
=CRASH REPORT==== 9-Dec-2010::01:05:48 ===
crasher:
initial call: foo:init/1
pid: <0.58.0>
registered_name: []
exception exit: {blabla,[{foo,init,1},
{gen_server,init_it,6},
{proc_lib,init_p_do_apply,3}]}
Au-dessus nous voyons que nous avons un accident à foo:init/1
en raison d'une exception blabla
.
in function gen_server:init_it/6
ancestors: [foo_sup,<0.45.0>]
messages: []
links: [<0.57.0>]
dictionary: []
trap_exit: true
status: running
heap_size: 233
stack_size: 24
reductions: 108
neighbours:
Et maintenant le superviseur arrive à signaler le problème!
=SUPERVISOR REPORT==== 9-Dec-2010::01:05:48 ===
Supervisor: {local,foo_sup}
Context: start_error
Le contexte est exactement comme je l'ai dit que ce serait ...
Reason: {blabla,[{foo,init,1},
{gen_server,init_it,6},
{proc_lib,init_p_do_apply,3}]}
Et la raison attendue.
Offender: [{pid,undefined},
{name,foo},
{mfargs,{foo,start_link,[]}},
{restart_type,permanent},
{shutdown,2000},
{child_type,worker}]
J'émule une erreur d'exécution dans init avec erlang: error (blabla) et je ne vois jamais blabla dans le superviseur! – Bertaud
Ensuite, nous devons voir le code. –
init (Etat = # Etat {port = Port, name = Nom}) -> process_flag (trap_exit, true), Erlang: erreur (blabla), Opte = [binaire, {reuseaddr, true}, { carnet de commandes, 5}, {paquet, 0}, {actif, faux}, {nodelay, true}], \t \t cas gen_tcp: écouter (Port, opte) de \t {ok, socket_listen} -> \t logger: fmsg ("-> [~ s, init] Socket_Listen créé = ~ p", [Name, Socket_Listen]), \t \t {ok, handle_accept (État # état {socket_listen = Socket_Listen})}; \t \t \t {error, Motif} -> \t enregistreur \t: FMSG ("-> [~ s, init] Erreur, p ~ = Raison", [Nom, Raison]), {stop, Reason} \t fin. – Bertaud
Du code, s'il vous plaît? –
Tout d'abord, c'est une question générale! – Bertaud
La question est générale, mais votre idée est correcte. Normalement, 'terminate' est appelé. C'est pourquoi les gens demandent du code. –