Skip to content

Commit

Permalink
Merge pull request #2656 from rabbitmq/run-plugins-boot-steps-during-…
Browse files Browse the repository at this point in the history
…rabbit-start

rabbit: Run plugins' boot steps during rabbit start/2
(cherry picked from commit 67624cd)
  • Loading branch information
michaelklishin committed Jan 11, 2021
1 parent b67b842 commit edf9122
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 46 deletions.
43 changes: 28 additions & 15 deletions deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_boot_state.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@

-export([get/0,
set/1,
wait_for/2]).
wait_for/2,
has_reached/1,
has_reached_and_is_active/1]).

-define(PT_KEY_BOOT_STATE, {?MODULE, boot_state}).

-type boot_state() :: 'stopped' | 'booting' | 'ready' | 'stopping'.
-type boot_state() :: 'stopped' | 'booting' | 'core_started' | 'ready' | 'stopping'.

-export_type([boot_state/0]).

Expand All @@ -44,15 +46,15 @@ set(BootState) ->

-spec wait_for(boot_state(), timeout()) -> ok | {error, timeout}.
wait_for(BootState, infinity) ->
case is_reached(BootState) of
case has_reached(BootState) of
true -> ok;
false -> Wait = 200,
timer:sleep(Wait),
wait_for(BootState, infinity)
end;
wait_for(BootState, Timeout)
when is_integer(Timeout) andalso Timeout >= 0 ->
case is_reached(BootState) of
case has_reached(BootState) of
true -> ok;
false -> Wait = 200,
timer:sleep(Wait),
Expand All @@ -61,24 +63,35 @@ wait_for(BootState, Timeout)
wait_for(_, _) ->
{error, timeout}.

boot_state_idx(stopped) -> 0;
boot_state_idx(booting) -> 1;
boot_state_idx(ready) -> 2;
boot_state_idx(stopping) -> 3.
boot_state_idx(stopped) -> 0;
boot_state_idx(booting) -> 1;
boot_state_idx(core_started) -> 2;
boot_state_idx(ready) -> 3;
boot_state_idx(stopping) -> 4.

is_valid(BootState) ->
is_integer(boot_state_idx(BootState)).

is_reached(TargetBootState) ->
is_reached(?MODULE:get(), TargetBootState).
has_reached(TargetBootState) ->
has_reached(?MODULE:get(), TargetBootState).

is_reached(CurrentBootState, CurrentBootState) ->
has_reached(CurrentBootState, CurrentBootState) ->
true;
is_reached(stopping, stopped) ->
has_reached(stopping, stopped) ->
false;
is_reached(_CurrentBootState, stopped) ->
has_reached(_CurrentBootState, stopped) ->
true;
is_reached(stopped, _TargetBootState) ->
has_reached(stopped, _TargetBootState) ->
true;
is_reached(CurrentBootState, TargetBootState) ->
has_reached(CurrentBootState, TargetBootState) ->
boot_state_idx(TargetBootState) =< boot_state_idx(CurrentBootState).

has_reached_and_is_active(TargetBootState) ->
case ?MODULE:get() of
stopped ->
false;
CurrentBootState ->
has_reached(CurrentBootState, TargetBootState)
andalso
not has_reached(CurrentBootState, stopping)
end.
72 changes: 42 additions & 30 deletions deps/rabbit/src/rabbit.erl
Original file line number Diff line number Diff line change
Expand Up @@ -528,10 +528,9 @@ handle_app_error(Term) ->
is_booting() -> is_booting(node()).

is_booting(Node) when Node =:= node() ->
case rabbit_boot_state:get() of
booting -> true;
_ -> false
end;
rabbit_boot_state:has_reached_and_is_active(booting)
andalso
not rabbit_boot_state:has_reached(ready);
is_booting(Node) ->
case rpc:call(Node, rabbit, is_booting, []) of
{badrpc, _} = Err -> Err;
Expand Down Expand Up @@ -856,11 +855,30 @@ start(normal, []) ->
log_banner(),
warn_if_kernel_config_dubious(),
warn_if_disc_io_options_dubious(),
%% We run `rabbit` boot steps only for now. Plugins boot steps
%% will be executed as part of the postlaunch phase after they
%% are started.
rabbit_boot_steps:run_boot_steps([rabbit]),
run_postlaunch_phase(),

rabbit_log_prelaunch:debug(""),
rabbit_log_prelaunch:debug("== Plugins (prelaunch phase) =="),

rabbit_log_prelaunch:debug("Setting plugins up"),
%% `Plugins` contains all the enabled plugins, plus their
%% dependencies. The order is important: dependencies appear
%% before plugin which depend on them.
Plugins = rabbit_plugins:setup(),
rabbit_log_prelaunch:debug(
"Loading the following plugins: ~p", [Plugins]),
%% We can load all plugins and refresh their feature flags at
%% once, because it does not involve running code from the
%% plugins.
ok = app_utils:load_applications(Plugins),
ok = rabbit_feature_flags:refresh_feature_flags_after_app_load(
Plugins),

rabbit_log_prelaunch:debug(""),
rabbit_log_prelaunch:debug("== Boot steps =="),

ok = rabbit_boot_steps:run_boot_steps([rabbit | Plugins]),
run_postlaunch_phase(Plugins),
rabbit_boot_state:set(core_started),
{ok, SupPid}
catch
throw:{error, _} = Error ->
Expand All @@ -879,46 +897,39 @@ start(normal, []) ->
Error
end.

run_postlaunch_phase() ->
spawn(fun() -> do_run_postlaunch_phase() end).
run_postlaunch_phase(Plugins) ->
spawn(fun() -> do_run_postlaunch_phase(Plugins) end).

do_run_postlaunch_phase() ->
do_run_postlaunch_phase(Plugins) ->
%% Once RabbitMQ itself is started, we need to run a few more steps,
%% in particular start plugins.
rabbit_log_prelaunch:debug(""),
rabbit_log_prelaunch:debug("== Postlaunch phase =="),

try
%% Successful boot resets node maintenance state.
rabbit_log_prelaunch:debug(""),
rabbit_log_prelaunch:debug("== Plugins =="),
rabbit_log_prelaunch:info("Resetting node maintenance status"),
_ = rabbit_maintenance:unmark_as_being_drained(),

rabbit_log_prelaunch:debug(""),
rabbit_log_prelaunch:debug("== Plugins (postlaunch phase) =="),

rabbit_log_prelaunch:debug("Setting plugins up"),
%% `Plugins` contains all the enabled plugins, plus their
%% dependencies. The order is important: dependencies appear
%% before plugin which depend on them.
Plugins = rabbit_plugins:setup(),
rabbit_log_prelaunch:debug(
"Starting the following plugins: ~p", [Plugins]),
%% We can load all plugins and refresh their feature flags at
%% once, because it does not involve running code from the
%% plugins.
app_utils:load_applications(Plugins),
ok = rabbit_feature_flags:refresh_feature_flags_after_app_load(
Plugins),
%% However, we want to run their boot steps and actually start
%% them one by one, to ensure a dependency is fully started
%% before a plugin which depends on it gets a chance to start.
rabbit_log_prelaunch:debug(
"Starting the following plugins: ~p", [Plugins]),
lists:foreach(
fun(Plugin) ->
ok = rabbit_boot_steps:run_boot_steps([Plugin]),
case application:ensure_all_started(Plugin) of
{ok, _} -> ok;
Error -> throw(Error)
end
end, Plugins),

%% Export definitions after all plugins have been enabled,
%% see rabbitmq/rabbitmq-server#2384
%% see rabbitmq/rabbitmq-server#2384.
case rabbit_definitions:maybe_load_definitions() of
ok -> ok;
DefLoadError -> throw(DefLoadError)
Expand All @@ -933,8 +944,9 @@ do_run_postlaunch_phase() ->
%% The node is ready: mark it as such and log it.
%% NOTE: PLEASE DO NOT ADD CRITICAL NODE STARTUP CODE AFTER THIS.
ok = rabbit_lager:broker_is_started(),
ok = log_broker_started(
rabbit_plugins:strictly_plugins(rabbit_plugins:active())),
ActivePlugins = rabbit_plugins:active(),
StrictlyPlugins = rabbit_plugins:strictly_plugins(ActivePlugins),
ok = log_broker_started(StrictlyPlugins),

rabbit_log_prelaunch:info("Resetting node maintenance status"),
%% successful boot resets node maintenance state
Expand Down
2 changes: 1 addition & 1 deletion deps/rabbit/src/rabbit_direct.erl
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ auth_fun({Username, Password}, VHost, ExtraAuthProps) ->
connect(Creds, VHost, Protocol, Pid, Infos) ->
ExtraAuthProps = extract_extra_auth_props(Creds, VHost, Pid, Infos),
AuthFun = auth_fun(Creds, VHost, ExtraAuthProps),
case rabbit:is_running() of
case rabbit_boot_state:has_reached_and_is_active(core_started) of
true ->
case whereis(rabbit_direct_client_sup) of
undefined ->
Expand Down

0 comments on commit edf9122

Please sign in to comment.