Skip to content

Commit b9328fe

Browse files
authored
Merge pull request #12466 from rabbitmq/enable-required-feature-flags-during-sync
rabbit_feature_flags: Introduce hard vs. soft required feature flags
2 parents beebf76 + 3c15d7e commit b9328fe

File tree

8 files changed

+301
-64
lines changed

8 files changed

+301
-64
lines changed

deps/rabbit/src/rabbit_core_ff.erl

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,81 +10,93 @@
1010
-rabbit_feature_flag(
1111
{classic_mirrored_queue_version,
1212
#{desc => "Support setting version for classic mirrored queues",
13-
stability => required
13+
stability => required,
14+
require_level => hard
1415
}}).
1516

1617
-rabbit_feature_flag(
1718
{quorum_queue,
1819
#{desc => "Support queues of type `quorum`",
1920
doc_url => "https://www.rabbitmq.com/docs/quorum-queues",
20-
stability => required
21+
stability => required,
22+
require_level => hard
2123
}}).
2224

2325
-rabbit_feature_flag(
2426
{stream_queue,
2527
#{desc => "Support queues of type `stream`",
2628
doc_url => "https://www.rabbitmq.com/docs/stream",
2729
stability => required,
30+
require_level => hard,
2831
depends_on => [quorum_queue]
2932
}}).
3033

3134
-rabbit_feature_flag(
3235
{implicit_default_bindings,
3336
#{desc => "Default bindings are now implicit, instead of "
3437
"being stored in the database",
35-
stability => required
38+
stability => required,
39+
require_level => hard
3640
}}).
3741

3842
-rabbit_feature_flag(
3943
{virtual_host_metadata,
4044
#{desc => "Virtual host metadata (description, tags, etc)",
41-
stability => required
45+
stability => required,
46+
require_level => hard
4247
}}).
4348

4449
-rabbit_feature_flag(
4550
{maintenance_mode_status,
4651
#{desc => "Maintenance mode status",
47-
stability => required
52+
stability => required,
53+
require_level => hard
4854
}}).
4955

5056
-rabbit_feature_flag(
51-
{user_limits,
52-
#{desc => "Configure connection and channel limits for a user",
53-
stability => required
57+
{user_limits,
58+
#{desc => "Configure connection and channel limits for a user",
59+
stability => required,
60+
require_level => hard
5461
}}).
5562

5663
-rabbit_feature_flag(
5764
{stream_single_active_consumer,
5865
#{desc => "Single active consumer for streams",
5966
doc_url => "https://www.rabbitmq.com/docs/stream",
6067
stability => required,
68+
require_level => hard,
6169
depends_on => [stream_queue]
6270
}}).
6371

6472
-rabbit_feature_flag(
65-
{feature_flags_v2,
66-
#{desc => "Feature flags subsystem V2",
67-
stability => required
73+
{feature_flags_v2,
74+
#{desc => "Feature flags subsystem V2",
75+
stability => required,
76+
require_level => hard
6877
}}).
6978

7079
-rabbit_feature_flag(
7180
{direct_exchange_routing_v2,
72-
#{desc => "v2 direct exchange routing implementation",
73-
stability => required,
74-
depends_on => [feature_flags_v2, implicit_default_bindings]
81+
#{desc => "v2 direct exchange routing implementation",
82+
stability => required,
83+
require_level => hard,
84+
depends_on => [feature_flags_v2, implicit_default_bindings]
7585
}}).
7686

7787
-rabbit_feature_flag(
7888
{listener_records_in_ets,
79-
#{desc => "Store listener records in ETS instead of Mnesia",
80-
stability => required,
81-
depends_on => [feature_flags_v2]
89+
#{desc => "Store listener records in ETS instead of Mnesia",
90+
stability => required,
91+
require_level => hard,
92+
depends_on => [feature_flags_v2]
8293
}}).
8394

8495
-rabbit_feature_flag(
8596
{tracking_records_in_ets,
8697
#{desc => "Store tracking records in ETS instead of Mnesia",
8798
stability => required,
99+
require_level => hard,
88100
depends_on => [feature_flags_v2]
89101
}}).
90102

@@ -94,6 +106,7 @@
94106
doc_url => "https://github.com/rabbitmq/rabbitmq-server/issues/5931",
95107
%%TODO remove compatibility code
96108
stability => required,
109+
require_level => hard,
97110
depends_on => [stream_queue]
98111
}}).
99112

@@ -102,6 +115,7 @@
102115
#{desc => "Support for restarting streams with optional preferred next leader argument."
103116
"Used to implement stream leader rebalancing",
104117
stability => required,
118+
require_level => hard,
105119
depends_on => [stream_queue]
106120
}}).
107121

@@ -110,20 +124,23 @@
110124
#{desc => "Bug fix to unblock a group of consumers in a super stream partition",
111125
doc_url => "https://github.com/rabbitmq/rabbitmq-server/issues/7743",
112126
stability => required,
127+
require_level => hard,
113128
depends_on => [stream_single_active_consumer]
114129
}}).
115130

116131
-rabbit_feature_flag(
117132
{stream_filtering,
118133
#{desc => "Support for stream filtering.",
119134
stability => required,
135+
require_level => hard,
120136
depends_on => [stream_queue]
121137
}}).
122138

123139
-rabbit_feature_flag(
124140
{message_containers,
125141
#{desc => "Message containers.",
126142
stability => required,
143+
require_level => hard,
127144
depends_on => [feature_flags_v2]
128145
}}).
129146

@@ -154,6 +171,7 @@
154171
#{desc => "A new internal command that is used to update streams as "
155172
"part of a policy.",
156173
stability => required,
174+
require_level => hard,
157175
depends_on => [stream_queue]
158176
}}).
159177

deps/rabbit/src/rabbit_feature_flags.erl

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
init/0,
106106
get_state/1,
107107
get_stability/1,
108+
get_require_level/1,
108109
check_node_compatibility/1, check_node_compatibility/2,
109110
sync_feature_flags_with_cluster/2,
110111
refresh_feature_flags_after_app_load/0,
@@ -147,6 +148,7 @@
147148
-type feature_props() :: #{desc => string(),
148149
doc_url => string(),
149150
stability => stability(),
151+
require_level => require_level(),
150152
depends_on => [feature_name()],
151153
callbacks =>
152154
#{callback_name() => callback_fun_name()}}.
@@ -183,6 +185,7 @@
183185
desc => string(),
184186
doc_url => string(),
185187
stability => stability(),
188+
require_level => require_level(),
186189
depends_on => [feature_name()],
187190
callbacks =>
188191
#{callback_name() => callback_fun_name()},
@@ -207,6 +210,15 @@
207210
%% Experimental feature flags are not enabled by default on a fresh RabbitMQ
208211
%% node. They must be enabled by the user.
209212

213+
-type require_level() :: hard | soft.
214+
%% The level of requirement of a feature flag.
215+
%%
216+
%% A hard required feature flags must be enabled before a RabbitMQ node is
217+
%% upgraded to a version where it is required.
218+
%%
219+
%% A soft required feature flag will be automatically enabled when a RabbitMQ
220+
%% node is upgraded to a version where it is required.
221+
210222
-type callback_fun_name() :: {Module :: module(), Function :: atom()}.
211223
%% The name of the module and function to call when changing the state of
212224
%% the feature flag.
@@ -755,6 +767,48 @@ get_stability(FeatureProps) when ?IS_DEPRECATION(FeatureProps) ->
755767
permitted_by_default -> experimental
756768
end.
757769

770+
-spec get_require_level
771+
(FeatureName) -> RequireLevel | undefined when
772+
FeatureName :: feature_name(),
773+
RequireLevel :: require_level() | none;
774+
(FeatureProps) -> RequireLevel when
775+
FeatureProps ::
776+
feature_props_extended() |
777+
rabbit_deprecated_features:feature_props_extended(),
778+
RequireLevel :: require_level() | none.
779+
%% @doc
780+
%% Returns the requirement level of a feature flag.
781+
%%
782+
%% The possible requirement levels are:
783+
%% <ul>
784+
%% <li>`hard': the feature flag must be enabled before the RabbitMQ node is
785+
%% upgraded to a version where it is hard required.</li>
786+
%% <li>`soft': the feature flag will be automatically enabled wher a RabbitMQ
787+
%% node is upgraded to a version where it is soft required.</li>
788+
%% <li>`none': the feature flag is not required.</li>
789+
%% </ul>
790+
%%
791+
%% @param FeatureName The name of the feature flag to check.
792+
%% @param FeatureProps A feature flag properties map.
793+
%% @returns `hard', `soft' or `none', or `undefined' if the given feature flag
794+
%% name doesn't correspond to a known feature flag.
795+
796+
get_require_level(FeatureName) when is_atom(FeatureName) ->
797+
case rabbit_ff_registry_wrapper:get(FeatureName) of
798+
undefined -> undefined;
799+
FeatureProps -> get_require_level(FeatureProps)
800+
end;
801+
get_require_level(FeatureProps) when ?IS_FEATURE_FLAG(FeatureProps) ->
802+
case get_stability(FeatureProps) of
803+
required -> maps:get(require_level, FeatureProps, soft);
804+
_ -> none
805+
end;
806+
get_require_level(FeatureProps) when ?IS_DEPRECATION(FeatureProps) ->
807+
case get_stability(FeatureProps) of
808+
required -> hard;
809+
_ -> none
810+
end.
811+
758812
%% -------------------------------------------------------------------
759813
%% Feature flags registry.
760814
%% -------------------------------------------------------------------
@@ -913,6 +967,7 @@ assert_feature_flag_is_valid(FeatureName, FeatureProps) ->
913967
ValidProps = [desc,
914968
doc_url,
915969
stability,
970+
require_level,
916971
depends_on,
917972
callbacks],
918973
?assertEqual([], maps:keys(FeatureProps) -- ValidProps),
@@ -1363,7 +1418,7 @@ run_feature_flags_mod_on_remote_node(Node, Function, Args, Timeout) ->
13631418
sync_feature_flags_with_cluster([] = _Nodes, true = _NodeIsVirgin) ->
13641419
rabbit_ff_controller:enable_default();
13651420
sync_feature_flags_with_cluster([] = _Nodes, false = _NodeIsVirgin) ->
1366-
ok;
1421+
rabbit_ff_controller:enable_required();
13671422
sync_feature_flags_with_cluster(Nodes, _NodeIsVirgin) ->
13681423
%% We don't use `rabbit_nodes:filter_running()' here because the given
13691424
%% `Nodes' list may contain nodes which are not members yet (the cluster

0 commit comments

Comments
 (0)