gen_tcp:connect will close when using supervisor.

Karl Velicka karolis.velicka@REDACTED
Fri Nov 20 10:01:39 CET 2020


Hi,

I ran your program with a small difference and found some threads to pull
on. I added process_flag(trap_exit, true), to ttest:init. Running `erl
-noshell -s ttest start` now gives different output, and the other side of
the socket gets closed:

gen_server start id is <0.9.0>
connect id is <0.78.0>
init id is <0.78.0>
gen_server id is <0.78.0>
=ERROR REPORT==== 20-Nov-2020::08:46:30.930438 ===
** Generic server ttest terminating
** Last message in was {'EXIT',<0.9.0>,normal}
** When Server state == []
** Reason for termination ==
** {function_clause,[{ttest,terminate,
                            [normal,[]],
                            [{file,"ttest.erl"},{line,29}]},
                     {gen_server,try_terminate,3,
                                 [{file,"gen_server.erl"},{line,718}]},
                     {gen_server,terminate,10,
                                 [{file,"gen_server.erl"},{line,903}]},
                     {proc_lib,init_p_do_apply,3,
                               [{file,"proc_lib.erl"},{line,226}]}]}

=CRASH REPORT==== 20-Nov-2020::08:46:30.954039 ===
  crasher:
    initial call: ttest:init/1
    pid: <0.78.0>
    registered_name: ttest
    exception error: no function clause matching ttest:terminate(normal,[])
(ttest.erl, line 29)
      in function  gen_server:try_terminate/3 (gen_server.erl, line 718)
      in call from gen_server:terminate/10 (gen_server.erl, line 903)
    ancestors: [<0.9.0>]
    message_queue_len: 0
    messages: []
    links: [#Port<0.6>]
    dictionary: []
    trap_exit: true
    status: running
    heap_size: 4185
    stack_size: 28
    reductions: 6011
  neighbours:

The reason why this particular error gets printed is somewhat accidental,
but the key bit is "** Last message in was {'EXIT',<0.9.0>,normal}" - this
suggests that the process that was starting your gen_server (<0.9.0>) has
itself exited with the reason `normal`, presumably right after running the
function specified by the `-s` flag.

There's two key things to note here:

* a supervisor itself is implemented as a gen_server that traps exits. That
is, it will notice any exit signal sent to it (barring `kill` perhaps?),
and react to it
* normally (i.e. in absence of trap_exit), when two processes are linked an
one of them exits with the reason `normal`, the other one does _not_exit

The result of this is that the supervisor you're starting notices <0.9.0>
exiting and exits itself, whereas your gen_server does not. This also
explains why starting the supervisor and unlinking it also seemingly fixes
the problem - in that case the exit signal of <0.9.0> never reaches the
supervisor as there's no link by the time it exits (which seems to be right
after tt_sup:start_link/start_shell returns).

The solution I'd suggest is making a rudimentary application (
https://erlang.org/doc/design_principles/applications.html) containing your
module and supervisor, or simply continue with the `unlink` solution if
you're just messing around with some non-serious code.

Hope that helps!

Karl


On Wed, 18 Nov 2020 at 23:27, George Hope <george@REDACTED> wrote:

> I have a simple gen_server which connects to a tcp port, when I run
> gen_server directly:
> erl -noshell -s ttest start
> it works fine, But when I run:
> erl -noshell -s tt_sup start_link
> the connection will be closed instantly, it will work if I unlink the
> supervisor.
> How could I run my simple gen_server with supervisor ?
>
>
> -module(tt_sup).
> -behaviour(supervisor).
> -export([init/1, start_link/0, start_shell/0]).
>
> start_link() ->
>     io:format("Supervisor started with PID~p~n", [self()]),
>     {ok, Pid} = supervisor:start_link(tt_sup, []),
>     io:format("Supervisor PID=~p~n", [Pid]),
>     {ok, Pid}.
>
> start_shell() ->
>     io:format("Supervisor started with PID~p~n", [self()]),
>     {ok, Pid} = supervisor:start_link(tt_sup, []),
>     io:format("Supervisor PID=~p~n", [Pid]),
>     unlink(Pid),
>     {ok, Pid}.
>
> init(_Args) ->
>     SupFlags = #{strategy => one_for_one},
>     Child = [#{id => ttest, start => {ttest, start, []},
>                restart => permanent, shutdown => brutal_kill,
>                type => worker, modules => [ttest]}],
>     {ok, {SupFlags, Child}}.
>
>
> -module(ttest).
>
> -export([start/0,init/1,handle_cast/2,handle_call/3,handle_info/2,terminate/2,connect/1]).
> -behaviour(gen_server).
>
> start() ->
>        io:format("gen_server start id is ~p~n",[self()]),
>        {ok,Pid} = gen_server:start_link({local,ttest},ttest,[],[]),
>        io:format("gen_server id is ~p~n",[Pid]),
>        connect(Pid),
>        {ok,Pid}.
>
> init(_Args) ->
>     io:format("init id is ~p~n",[self()]),
>         {ok,[]}.
> handle_call({tcp,Socket,Bin},_From,States) ->
>         {reply,States,States}.
> handle_info({tcp,Socket,Bin},States) ->
>         io:format("got info msg"),
>         {noreply,States}.
>
> handle_cast({send,Msg},States) ->
>         {reply,States}.
>
> connect(I) ->
>     io:format("connect id is ~p~n",[self()]),
>         {ok,Socket}
> =gen_tcp:connect("localhost",6000,[binary,{active,true}]),
>         gen_tcp:controlling_process(Socket,I).
>
> terminate(shutdown, State) ->
>     io:format("terminating"),
>     ok.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20201120/6f982404/attachment.htm>


More information about the erlang-questions mailing list