diff options
| -rw-r--r-- | apps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl | 3 | ||||
| -rw-r--r-- | apps/rabbitmq_prelaunch/src/rabbit_prelaunch_sighandler.erl | 85 | ||||
| -rwxr-xr-x | scripts/rabbitmq-server | 11 | ||||
| -rw-r--r-- | src/rabbit.erl | 6 | ||||
| -rw-r--r-- | src/rabbit_os_signal_handler.erl | 60 |
5 files changed, 97 insertions, 68 deletions
diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl index b564fadf51..ef15f47a75 100644 --- a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl @@ -48,6 +48,9 @@ do_run() -> %% Configure dbg if requested. rabbit_prelaunch_early_logging:enable_quick_dbg(rabbit_env:dbg_config()), + %% Setup signal handler. + ok = rabbit_prelaunch_sighandler:setup(), + %% We assert Mnesia is stopped before we run the prelaunch %% phases. %% diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_sighandler.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_sighandler.erl new file mode 100644 index 0000000000..a6b5d3c2f7 --- /dev/null +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_sighandler.erl @@ -0,0 +1,85 @@ +-module(rabbit_prelaunch_sighandler). +-behaviour(gen_event). + +-export([setup/0, + init/1, + handle_event/2, + handle_call/2, + handle_info/2, + terminate/2, + code_change/3]). + +%% CAUTION: Signal handling in this module must be kept consistent +%% with the same handling in rabbitmq-server(8). + +%% #{signal => default | ignore | stop}. +-define(SIGNALS_HANDLED_BY_US, + #{ + %% SIGHUP is often used to reload the configuration or reopen + %% log files after they were rotated. We don't support any + %% of those two cases, so ignore it for now, until we can do + %% something about it. + sighup => ignore, + + %% SIGTSTP is triggered by Ctrl+Z to pause a program. However + %% we can't handle SIGCONT, the signal used to resume the + %% program. Unfortunately, it makes a SIGTSTP handler less + %% useful here. + sigtstp => ignore + }). + +-define(SIGNAL_HANDLED_BY_ERLANG(Signal), + Signal =:= sigusr1 orelse + Signal =:= sigquit orelse + Signal =:= sigterm). + +-define(SERVER, erl_signal_server). + +setup() -> + case whereis(?SERVER) of + undefined -> + ok; + _ -> + case lists:member(?MODULE, gen_event:which_handlers(?SERVER)) of + true -> ok; + false -> gen_event:add_handler(?SERVER, ?MODULE, []) + end + end. + +init(_Args) -> + maps:fold( + fun + (Signal, _, Ret) when ?SIGNAL_HANDLED_BY_ERLANG(Signal) -> Ret; + (Signal, default, ok) -> os:set_signal(Signal, default); + (Signal, ignore, ok) -> os:set_signal(Signal, ignore); + (Signal, _, ok) -> os:set_signal(Signal, handle) + end, ok, ?SIGNALS_HANDLED_BY_US), + {ok, #{}}. + +handle_event(Signal, State) when ?SIGNAL_HANDLED_BY_ERLANG(Signal) -> + {ok, State}; +handle_event(Signal, State) -> + case ?SIGNALS_HANDLED_BY_US of + #{Signal := stop} -> + error_logger:info_msg( + "~s received - shutting down~n", + [string:uppercase(atom_to_list(Signal))]), + ok = init:stop(); + _ -> + error_logger:info_msg( + "~s received - unhandled signal~n", + [string:uppercase(atom_to_list(Signal))]) + end, + {ok, State}. + +handle_info(_, State) -> + {ok, State}. + +handle_call(_, State) -> + {ok, ok, State}. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +terminate(_Args, _State) -> + ok. diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server index 5939c845d2..0976c5566a 100755 --- a/scripts/rabbitmq-server +++ b/scripts/rabbitmq-server @@ -141,7 +141,9 @@ else # Signal handlers. They all stop RabbitMQ properly, using # rabbitmqctl stop. This script will exit with different exit codes: - # SIGHUP SIGTERM SIGTSTP + # SIGHUP, SIGTSTP + SIGCONT + # Ignored until we implement a useful behavior. + # SIGTERM # Exits 0 since this is considered a normal process termination. # SIGINT # Exits 128 + $signal_number where $signal_number is 2 for SIGINT (see @@ -150,7 +152,12 @@ else # don't need to specify this exit code because the shell propagates it. # Unfortunately, the signal handler doesn't work as expected in Dash, # thus we need to explicitly restate the exit code. - trap "stop_rabbitmq_server; exit 0" HUP TERM TSTP + # + # The behaviors below should remain consistent with the + # equivalent signal handlers in the Erlang code + # (see apps/rabbitmq_prelaunch/src/rabbit_prelaunch_sighandler.erl). + trap '' HUP TSTP CONT + trap "stop_rabbitmq_server; exit 0" TERM trap "stop_rabbitmq_server; exit 130" INT start_rabbitmq_server "$@" & diff --git a/src/rabbit.erl b/src/rabbit.erl index 0f98e50504..12b12bb222 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -235,12 +235,6 @@ {requires, pre_flight} ]}). --rabbit_boot_step({os_signal_handler, - [{description, "registers an OS signal handler"}, - {mfa, {rabbit_sup, start_restartable_child, - [rabbit_os_signal_handler]}}, - {requires, pre_flight}]}). - -rabbit_boot_step({direct_client, [{description, "direct client"}, {mfa, {rabbit_direct, boot, []}}, diff --git a/src/rabbit_os_signal_handler.erl b/src/rabbit_os_signal_handler.erl deleted file mode 100644 index d221143379..0000000000 --- a/src/rabbit_os_signal_handler.erl +++ /dev/null @@ -1,60 +0,0 @@ --module(rabbit_os_signal_handler). - --behaviour(gen_event). - --export([start_link/0, init/1, - handle_event/2, handle_call/2, handle_info/2, - terminate/2]). - -%% -%% API -%% - -start_link() -> - rabbit_log:info("Swapping OS signal event handler (erl_signal_server) for our own"), - %% delete any previous incarnations, otherwise we would be accumulating - %% handlers - _ = gen_event:delete_handler(erl_signal_server, ?MODULE, []), - %% swap the standard OTP signal handler if there is one - ok = gen_event:swap_sup_handler( - erl_signal_server, - %% what to swap - {erl_signal_handler, []}, - %% new event handler - {?MODULE, []}), - gen_event:start_link({local, ?MODULE}). - -init(_) -> - {ok, #{}}. - -handle_event(sigterm, State) -> - rabbit_log:info("Received a SIGTERM, will shut down gracefully"), - rabbit:stop_and_halt(), - {ok, State}; -handle_event(sigquit, State) -> - rabbit_log:info("Received a SIGQUIT, will shut down gracefully"), - rabbit:stop_and_halt(), - {ok, State}; -handle_event(sigusr1, State) -> - rabbit_log:info("Received a SIGUSR1, ignoring it"), - {ok, State}; -handle_event(sigusr2, State) -> - rabbit_log:info("Received a SIGUSR2, ignoring it"), - {ok, State}; -%% note: SIGHUP can/will be handled by shells and process managers -handle_event(sighup, State) -> - rabbit_log:info("Received a SIGHUP, ignoring it"), - {ok, State}; -handle_event(Msg, S) -> - %% delegate all unknown events to the default OTP signal handler - erl_signal_handler:handle_event(Msg, S), - {ok, S}. - -handle_info(_, State) -> - {ok, State}. - -handle_call(_Request, State) -> - {ok, ok, State}. - -terminate(_Args, _State) -> - ok. |
