Re: gen_tcp:connect will close when using supervisor.

Karl Velicka <[email protected]>
Newsgroups gmane.comp.lang.erlang.general
Message-ID <CANxL2L5cUpoOzXamYDkFr9yCGk3T1MZS4v9t7haqHw4qu7EfDw@mail.gmail.com>
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 <[email protected]> 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.
>
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.