Closed mrramachari closed 7 months ago
That will depend on how you shut down the shell, and where the function runs.
If you use init:stop()
or init:stop(0)
, the signal is going to propagate down from the application controller and to individual supervisors, which will send a shutdown signal to individual OTP processes. If the child traps exits, then you will be able to handle the shutdown in the terminate callback, but it will be indistinct from any other termination and invisible to a brutal shutdown of the shell (eg. with ctrl+c
in the escript or whatever).
Going through all the ways a shell can be terminated of that kind is a bit more work and I'd redirect you to the erlang forums about that, because it covers a lot more ground than rebar3 itself (which is just a tiny hack over escripts to simulate a full shell but can't cover all the capabilities of it)
Another option that exists and might be more in line with what you look for is os:set_signal/2
along with registering a event handler in erl_signal_server
.
Thank your for your reply,Yes I'm trying to execute a function just before I brutally terminate the rebar3 shell using abort option. I went through os:set_signal/2 func ,but im facing trouble trying to understand it ,perhaps if you could give me an example of how to do it ,it will be very helpful for me,thank you,below is a code snippet which I tried.
-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([]) ->
SupFlags = #{strategy => one_for_all,
intensity => 0,
period => 1},
ChildSpecs = [],
process_flag(trap_exit, true),
RestartStrategy = {one_for_one, 8, 10},
MonitorPid = spawn(fun() -> handle() end),
link(MonitorPid),
os:set_signal('sigtstp', 'handle'),
{ok, {SupFlags, ChildSpecs}}.
handle() ->
receive
'sigtstp' ->
io:format("Exit signal received. Goodbye!\n")
end.
so you're calling os:set_signal/2
which makes the signal go to the erl_signal_server
process. That process is a gen_event worker, which means you would have to register a callback module for it.
This requires defining two callbacks at least: init
and handle_event
, and then registering it. There's a more complete tutorial in the official docs if you want, and an older one in LYSE.
Thank you for your reply once again, actually my main goal is to execute a cleanup type function which I can use to truncate a table of a database or something like that,I want that to happen when the shell gets closed.I tried doing the gen_event module but still I'm facing difficulties to start it from the supervisor, also if i start it manually its not capturing the exit signals when i abort.
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 terminal_logger which is a gen_event module
-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 is 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
Your supervisor is going for {terminal_logger, start_link, []}
but the function exported is terminal_logger:start/0
. You also do not need to supervise the callback module because it should run within erl_signal_server
.
At this point though I'm thinking this is more general Erlang help you require and this is off-topic for the rebar3 build tool. I would encourage you to move the discussion somewhere like erlangforums.com.
Thank you.
I have an erlang supervsior,and an application.I want a function to be executed just when I close or abort the rebar3 shell.