diff --git a/deps/rabbit/src/rabbit_core_ff.erl b/deps/rabbit/src/rabbit_core_ff.erl
index c83548030829..0c0cb3e17da2 100644
--- a/deps/rabbit/src/rabbit_core_ff.erl
+++ b/deps/rabbit/src/rabbit_core_ff.erl
@@ -146,9 +146,10 @@
-rabbit_feature_flag(
{khepri_db,
- #{desc => "New Raft-based metadata store. Fully supported as of RabbitMQ 4.0",
+ #{desc => "New Raft-based metadata store.",
doc_url => "https://www.rabbitmq.com/docs/next/metadata-store",
stability => experimental,
+ experiment_level => supported,
depends_on => [feature_flags_v2,
direct_exchange_routing_v2,
maintenance_mode_status,
diff --git a/deps/rabbit/src/rabbit_feature_flags.erl b/deps/rabbit/src/rabbit_feature_flags.erl
index d50e30375c81..8425dafa4cef 100644
--- a/deps/rabbit/src/rabbit_feature_flags.erl
+++ b/deps/rabbit/src/rabbit_feature_flags.erl
@@ -106,6 +106,7 @@
get_state/1,
get_stability/1,
get_require_level/1,
+ get_experiment_level/1,
check_node_compatibility/1, check_node_compatibility/2,
sync_feature_flags_with_cluster/2,
refresh_feature_flags_after_app_load/0,
@@ -149,6 +150,7 @@
doc_url => string(),
stability => stability(),
require_level => require_level(),
+ experiment_level => experiment_level(),
depends_on => [feature_name()],
callbacks =>
#{callback_name() => callback_fun_name()}}.
@@ -186,6 +188,7 @@
doc_url => string(),
stability => stability(),
require_level => require_level(),
+ experiment_level => experiment_level(),
depends_on => [feature_name()],
callbacks =>
#{callback_name() => callback_fun_name()},
@@ -219,6 +222,24 @@
%% A soft required feature flag will be automatically enabled when a RabbitMQ
%% node is upgraded to a version where it is required.
+-type experiment_level() :: unsupported | supported.
+%% The level of support of an experimental feature flag.
+%%
+%% At first, an experimental feature flag is offered to give a chance to users
+%% to try it and give feedback as part of the design and development of the
+%% feature. At this stage, it is unsupported: it must not be enabled in a
+%% production environment and upgrade to a later version of RabbitMQ while
+%% this experimental feature flag is enabled is not supported.
+%%
+%% Then, the experimental feature flag becomes supported. At this point, it is
+%% stable enough that upgrading is guarantied and help will be provided.
+%% However it is not mature enough to be marked as stable (which would make it
+%% enabled by default in a new deployment or when running `rabbitmqctl
+%% enable_feature_flag all'.
+%%
+%% The next step is to change its stability to `stable'. Once done, the
+%% `experiment_level()' field is irrelevant.
+
-type callback_fun_name() :: {Module :: module(), Function :: atom()}.
%% The name of the module and function to call when changing the state of
%% the feature flag.
@@ -327,6 +348,8 @@
feature_state/0,
feature_states/0,
stability/0,
+ require_level/0,
+ experiment_level/0,
callback_fun_name/0,
callbacks/0,
callback_name/0,
@@ -696,13 +719,17 @@ info() ->
info(Options) when is_map(Options) ->
rabbit_ff_extra:info(Options).
--spec get_state(feature_name()) -> enabled | disabled | unavailable.
+-spec get_state(feature_name()) -> enabled |
+ state_changing |
+ disabled |
+ unavailable.
%% @doc
%% Returns the state of a feature flag.
%%
%% The possible states are:
%%
%%
`enabled': the feature flag is enabled.
+%%
`state_changing': the feature flag is being enabled.
%%
`disabled': the feature flag is supported by all nodes in the
%% cluster but currently disabled.
%%
`unavailable': the feature flag is unsupported by at least one
@@ -710,16 +737,20 @@ info(Options) when is_map(Options) ->
%%
%%
%% @param FeatureName The name of the feature flag to check.
-%% @returns `enabled', `disabled' or `unavailable'.
+%% @returns `enabled', `state_changing', `disabled' or `unavailable'.
get_state(FeatureName) when is_atom(FeatureName) ->
- IsEnabled = is_enabled(FeatureName),
+ IsEnabled = is_enabled(FeatureName, non_blocking),
case IsEnabled of
- true -> enabled;
- false -> case is_supported(FeatureName) of
- true -> disabled;
- false -> unavailable
- end
+ true ->
+ enabled;
+ state_changing ->
+ state_changing;
+ false ->
+ case is_supported(FeatureName) of
+ true -> disabled;
+ false -> unavailable
+ end
end.
-spec get_stability
@@ -809,6 +840,45 @@ get_require_level(FeatureProps) when ?IS_DEPRECATION(FeatureProps) ->
_ -> none
end.
+-spec get_experiment_level
+(FeatureName) -> ExperimentLevel | undefined when
+ FeatureName :: feature_name(),
+ ExperimentLevel :: experiment_level() | none;
+(FeatureProps) -> ExperimentLevel when
+ FeatureProps ::
+ feature_props_extended() |
+ rabbit_deprecated_features:feature_props_extended(),
+ ExperimentLevel :: experiment_level() | none.
+%% @doc
+%% Returns the experimental level of an experimental feature flag.
+%%
+%% The possible experiment levels are:
+%%
+%%
`unsupported': the experimental feature flag must not be enabled in
+%% production and upgrades with it enabled is unsupported.
+%%
`supported': the experimental feature flag is not yet stable enough but
+%% upgrades are guarantied to be possible. This is returned too if the
+%% feature flag is stable or required.
<%
- var needs_enabling = false;
+ var nonreq_feature_flags = [];
for (var i = 0; i < feature_flags.length; i++) {
- var feature_flag = feature_flags[i];
- if (feature_flag.state == "disabled" && feature_flag.stability != "experimental") {
- needs_enabling = true;
- }
+ if (feature_flags[i].stability == 'required')
+ continue;
+ nonreq_feature_flags.push(feature_flags[i]);
}
- if (needs_enabling) { %>
-
- All stable feature flags must be enabled after completing an upgrade. Without enabling all flags, upgrading to future minor or major versions of RabbitMQ may not be possible. [Learn more]
-
- <% } %>
+ %>
+
+
+ All stable feature flags must be enabled after completing an upgrade.
+ Without enabling all flags, upgrading to future minor or major versions
+ of RabbitMQ may not be possible.
+ [Learn more]
+
+
+
Feature Flags
-<%= filter_ui(feature_flags) %>
-
-<% if (feature_flags.length > 0) { %>
-
-
-
-
<%= fmt_sort('Name', 'name') %>
-
<%= fmt_sort('State', 'state') %>
-
Description
-
-
-
- <%
- for (var i = 0; i < feature_flags.length; i++) {
- var feature_flag = feature_flags[i];
- if (feature_flag.stability == "required") {
- /* Hide required feature flags. There is nothing the user can do
- * about them and they just add noise to the UI. */
- continue;
- }
- if (feature_flag.stability == "experimental") {
- continue;
- }
- var state_color = "grey";
- if (feature_flag.state == "enabled") {
- state_color = "green";
- } else if (feature_flag.state == "disabled") {
- state_color = "yellow";
- } else if (feature_flag.state == "unsupported") {
- state_color = "red";
- }
- %>
-
+<% if (nonreq_feature_flags.length > 0) { %>
+
+
+
-These flags can be enabled in production deployments after an appropriate amount of testing in non-production environments.
-
<%= fmt_sort('Name', 'name') %>
+
Specificities
<%= fmt_sort('State', 'state') %>
Description
<%
- for (var i = 0; i < feature_flags.length; i++) {
- var feature_flag = feature_flags[i];
- if (feature_flag.stability != "experimental") {
- continue;
- }
- var state_color = "grey";
- if (feature_flag.state == "enabled") {
- state_color = "green";
- } else if (feature_flag.state == "disabled") {
- state_color = "yellow";
- } else if (feature_flag.state == "unsupported") {
- state_color = "red";
- }
+ for (var i = 0; i < nonreq_feature_flags.length; i++) {
+ var feature_flag = nonreq_feature_flags[i];
%>