Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rabbit: Run plugins' boot steps during rabbit start/2 #2656

Merged
merged 1 commit into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -12,11 +12,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 @@ -36,15 +38,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 @@ -53,24 +55,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.
76 changes: 42 additions & 34 deletions deps/rabbit/src/rabbit.erl
Original file line number Diff line number Diff line change
Expand Up @@ -542,10 +542,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 @@ -870,11 +869,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 @@ -893,50 +911,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:info("Resetting node maintenance status"),
_ = rabbit_maintenance:unmark_as_being_drained(),

rabbit_log_prelaunch:debug(""),
rabbit_log_prelaunch:debug("== Plugins =="),
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),

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

%% 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 @@ -951,8 +958,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:debug("Marking ~s as running", [product_name()]),
rabbit_boot_state:set(ready)
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