How can I capture terminal abort exit and execute a function before termination?

This is my supervisor.

-module(my_web_app_sup).

-behaviour(supervisor).

-export([start_link/0]).

-export([init/1]).

-define(SERVER, ?MODULE).

start_link() ->
 
    supervisor:start_link({local, ?SERVER}, ?MODULE, []).

init([]) ->
     TerminalLogger = {terminal_logger, {terminal_logger, start_link, []}, permanent, 2000, worker, [terminal_logger]}, % Add terminal logger
      % gen_event:start({local, error_man}),
      % gen_event:add_handler(error_man, terminal_logger, []),
   Childern = [TerminalLogger],
RestartStrategy = {one_for_one, 8, 10},
	{ok, {RestartStrategy, Childern}}.


handle() ->
    receive        
        'sigtstp' ->
            io:format("Exit signal received. Goodbye!\n")
             end.

This is my module which im trying to capture exit signals.

-module(terminal_logger).
-moduledoc false.
-behaviour(gen_event).
-export([start/0, init/1,
         handle_event/2, handle_call/2, handle_info/2,
         terminate/2, code_change/3]).

-record(state,{}).

start() ->
    %% add signal handler
    case whereis(erl_signal_server) of
        %% in case of minimal mode
        undefined -> ok;
        _ ->
            gen_event:add_handler(erl_signal_server, terminal_logger, [])
    end.

init(_Args) ->
    {ok, #state{}}.

handle_event(sigusr1, S) ->
    erlang:halt("Received SIGUSR1"),
    {ok, S};
handle_event(sigquit, S) ->
    erlang:halt(),
    {ok, S};
handle_event(sigterm, S) ->
    error_logger:info_msg("SIGTERM received - shutting down~n"),
    ok = init:stop(),
    {ok, S};
handle_event(_SignalMsg, S) ->
            io:format("~n handle_event(_SignalMsg, S) ~n"),

    {ok, S}.

handle_info(_Info, S) ->
        io:format("~n handle_info(_Info, S) ->~n"),
    {ok, S}.

handle_call(_Request, S) ->
            io:format("~n handle_call(_Request, S)  ~n"),

    {ok, ok, S}.

code_change(_OldVsn, S, _Extra) ->
    {ok, S}.

terminate(_Args, _S) ->
        io:format("~nterminated~n"),

    ok.

This my terminal output.

rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
src/amf_sup.erl:49:1: Warning: function terminate/2 is unused

Erlang/OTP 26 [erts-14.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]
1> terminal_logger:start().
ok
2> 
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
a

Start MFA in children spec is ‘{terminal_logger, start_link, }’, but ‘start_link/0’ is not exported in ‘terminal_logger’

Also, seems like your suporvisor isn’t started. Make sure to have your app listed in shell config in rebar.config

1 Like

Thank you for your reply,I made few changes and now Im able to start it with my supervisor but Im still unable to capture exit signals.

This is my supervisor.

-module(shell_exit_sup).

-behaviour(supervisor).

-export([start_link/0]).

-export([init/1]).

-define(SERVER, ?MODULE).

start_link() ->
    supervisor:start_link({local, ?SERVER}, ?MODULE, []).

init([]) ->
    SupFlags = #{strategy => one_for_all,
                 intensity => 0,
                 period => 1},
 ChildSpecs = [
        #{id => shell_termination,
          start => {shell_termination, start, []},
          restart => permanent,
          shutdown => 5000,
          type => worker}
    ],    {ok, {SupFlags, ChildSpecs}}.

This is my gen_event module

-module(shell_termination).
-behaviour(gen_event).
-export([start/0, init/1,
         handle_event/2, handle_call/2, handle_info/2,
         terminate/2, code_change/3]).

-record(state,{}).

start() ->
    %% add signal handler
    case whereis(erl_signal_server) of
        %% in case of minimal mode
        undefined -> ok;
        _ ->
            gen_event:add_handler(erl_signal_server, erl_signal_handler, [])
    end,
    {ok,self()}.

init(_Args) ->
    {ok, #state{}}.

handle_event(sigusr1, S) ->
    erlang:halt("Received SIGUSR1"),
    {ok, S};
handle_event(sigquit, S) ->
    erlang:halt(),
    {ok, S};
handle_event(sigterm, S) ->
    error_logger:info_msg("SIGTERM received - shutting down~n"),
    ok = init:stop(),
    {ok, S};
handle_event(_SignalMsg, S) ->
        io:format("handle_info called "),

    {ok, S}.

handle_info(_Info, S) ->
    io:format("handle_info called "),
    {ok, S}.

handle_call(_Request, S) ->
        io:format("handle_info called "),

    {ok, ok, S}.

code_change(_OldVsn, S, _Extra) ->
    {ok, S}.

terminate(_Args, _S) ->
        io:format("handle_info called "),

    ok.

This is my terminal output.

rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling shell_exit
Erlang/OTP 26 [erts-14.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Eshell V14.1 (press Ctrl+G to abort, type help(). for help)
===> Booted shell_exit
1> 
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
a

In the example you’re trying to send SIGINT, right? It is intercepted by erlang shell and I don’t know if it’s forwarded to the user program. Try sending other signals which aren’t used by erang shell.

Also, make sure that os:set_signal/2 sets those signals to ‘handle’

1 Like

Thank you for your reply,I read somewhere that when I abort the rebar3 shell it behaves like erlang:halt() function,so I’m trying to capture whatever the signal it sends before exiting and execute a cleanup type function just before the exit of the program ,as per your suggestion I did set the os:set_signal(’ ',‘handle’) in fact I set all the options to handle and yet Im unable to capture the exit.

This is my module

-module(shell_termination).
-behaviour(gen_event).
-export([start/0, init/1,
         handle_event/2, handle_call/2, handle_info/2,
         terminate/2, code_change/3]).

-record(state,{}).

start() ->
    os:set_signal('sighup','handle'),
    os:set_signal('sigquit','handle'),
    os:set_signal('sigabrt' ,'handle'),
    os:set_signal('sigalrm','handle'),
    os:set_signal('sigterm','handle'),
    os:set_signal('sigusr1','handle'),
    os:set_signal('sigusr2','handle'),
    os:set_signal('sigchld','handle'),
    os:set_signal('sigstop','handle'),
    os:set_signal('sigtstp','handle'),




    %% add signal handler
    case whereis(erl_signal_server) of
        %% in case of minimal mode
        undefined -> ok;
        _ ->
            gen_event:add_handler(erl_signal_server, erl_signal_handler, [])
    end,
    {ok,self()}.

init(_Args) ->
    {ok, #state{}}.

handle_event(sigusr1, S) ->
    
    io:format("handle_info called "),
    % erlang:halt("Received SIGUSR1"),
    {ok, S};
handle_event(sigquit, S) ->
    io:format("handle_info called "),
    % erlang:halt(),
    {ok, S};
handle_event(sigterm, S) ->
    io:format("SIGTERM received - shutting down~n"),
    ok = init:stop(),
    {ok, S};
handle_event(_SignalMsg, S) ->
        io:format("handle_info called "),

    {ok, S}.

handle_info(_Info, S) ->
    io:format("handle_info called "),
    {ok, S}.

handle_call(_Request, S) ->
        io:format("handle_info called "),

    {ok, ok, S}.

code_change(_OldVsn, S, _Extra) ->
    {ok, S}.

terminate(_Args, _S) ->
        io:format("handle_info called "),

    ok.

This is my terminal output:

rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling shell_exit
Erlang/OTP 26 [erts-14.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Eshell V14.1 (press Ctrl+G to abort, type help(). for help)
===> Booted shell_exit
1> 
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
a