Search code examples
erlangerlang-supervisor

gen_tcp:connect will close when using supervisor


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:

erl -noshell -s tt_sup start_shell

How could I run my simple gen_tcp:connect (gen_server) with supervisor ?

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}}.

gen_server:

-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.

Solution

  • The process that runs the -s exits with normal when it has no more code to execute. The supervisor receives that signal and since it's from its parent, it exits (regardless of it being normal), as explained in gen_server:terminate/2 (supervisors are gen_servers with trap_exit active):

    Even if the gen_server process is not part of a supervision tree, this function is called if it receives an 'EXIT' message from its parent. Reason is the same as in the 'EXIT' message.

    I haven't tested your code, but if you add a process_flag(trap_exit, true) to your gen_server, you'll surely replicate this behaviour.