Skip to content

Commit 85ba1a8

Browse files
committed
rabbit_feature_flags: Accept "+feature1,feature2" in $RABBITMQ_FEATURE_FLAGS
[Why] Before this patch, the $RABBITMQ_FEATURE_FLAGS environment variable took an exhaustive list of feature flags to enable. This list overrode the default of enabling all stable feature flags. It made it inconvenient when a user wanted to enable an experimental feature flag like `khepri_db` while still leaving the default behavior. [How] $RABBITMQ_FEATURE_FLAGS now acceps the following syntax: RABBITMQ_FEATURE_FLAGS=+feature1,feature2 This will start RabbitMQ with all stable feature flags, plus `feature1` and `feature2`. For users setting `forced_feature_flags_on_init` in the config, the corresponding syntax is: {forced_feature_flags_on_init, {'+', [feature1, feature2]}}
1 parent e036aba commit 85ba1a8

File tree

2 files changed

+82
-53
lines changed

2 files changed

+82
-53
lines changed

deps/rabbit/src/rabbit_ff_controller.erl

Lines changed: 74 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -675,48 +675,64 @@ enable_task(FeatureNames) ->
675675
end.
676676

677677
enable_default_task() ->
678-
FeatureNames = get_forced_feature_flag_names(),
679-
case FeatureNames of
678+
Ret = get_forced_feature_flag_names(),
679+
case Ret of
680680
undefined ->
681681
?LOG_DEBUG(
682682
"Feature flags: starting an unclustered node for the first "
683683
"time: all stable feature flags will be enabled by default",
684684
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS}),
685685
{ok, Inventory} = collect_inventory_on_nodes([node()]),
686-
#{feature_flags := FeatureFlags} = Inventory,
687-
StableFeatureNames =
688-
maps:fold(
689-
fun(FeatureName, FeatureProps, Acc) ->
690-
Stability = rabbit_feature_flags:get_stability(
691-
FeatureProps),
692-
case Stability of
693-
stable -> [FeatureName | Acc];
694-
_ -> Acc
695-
end
696-
end, [], FeatureFlags),
686+
StableFeatureNames = get_stable_feature_flags(Inventory),
697687
enable_many(Inventory, StableFeatureNames);
698-
[] ->
688+
{abs, []} ->
699689
?LOG_DEBUG(
700690
"Feature flags: starting an unclustered node for the first "
701691
"time: all feature flags are forcibly left disabled from "
702692
"the $RABBITMQ_FEATURE_FLAGS environment variable",
703693
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS}),
704694
ok;
705-
_ ->
695+
{abs, FeatureNames} ->
706696
?LOG_DEBUG(
707697
"Feature flags: starting an unclustered node for the first "
708698
"time: only the following feature flags specified in the "
709699
"$RABBITMQ_FEATURE_FLAGS environment variable will be enabled: "
710-
"~tp",
700+
"~0tp",
711701
[FeatureNames],
712702
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS}),
713703
{ok, Inventory} = collect_inventory_on_nodes([node()]),
704+
enable_many(Inventory, FeatureNames);
705+
{rel, Plus, Minus} ->
706+
?LOG_DEBUG(
707+
"Feature flags: starting an unclustered node for the first "
708+
"time: all stable feature flags will be enabled, after "
709+
"applying changes from $RABBITMQ_FEATURE_FLAGS: adding ~0tp, "
710+
"skipping ~0tp",
711+
[Plus, Minus],
712+
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS}),
713+
{ok, Inventory} = collect_inventory_on_nodes([node()]),
714+
StableFeatureNames = get_stable_feature_flags(Inventory),
715+
FeatureNames = (StableFeatureNames -- Minus) ++ Plus,
714716
enable_many(Inventory, FeatureNames)
715717
end.
716718

719+
get_stable_feature_flags(#{feature_flags := FeatureFlags}) ->
720+
maps:fold(
721+
fun(FeatureName, FeatureProps, Acc) ->
722+
Stability = rabbit_feature_flags:get_stability(FeatureProps),
723+
case Stability of
724+
stable -> [FeatureName | Acc];
725+
_ -> Acc
726+
end
727+
end, [], FeatureFlags).
728+
717729
-spec get_forced_feature_flag_names() -> Ret when
718-
Ret :: FeatureNames | undefined,
719-
FeatureNames :: [rabbit_feature_flags:feature_name()].
730+
Ret :: Abs | Rel | undefined,
731+
Abs :: {abs, AbsNames},
732+
AbsNames :: [rabbit_feature_flags:feature_name()],
733+
Rel :: {rel, PlusNames, MinusNames},
734+
PlusNames :: [rabbit_feature_flags:feature_name()],
735+
MinusNames :: [rabbit_feature_flags:feature_name()].
720736
%% @doc Returns the (possibly empty) list of feature flags the user wants to
721737
%% enable out-of-the-box when starting a node for the first time.
722738
%%
@@ -737,59 +753,70 @@ enable_default_task() ->
737753
%% @private
738754

739755
get_forced_feature_flag_names() ->
740-
Ret = case get_forced_feature_flag_names_from_env() of
741-
undefined -> get_forced_feature_flag_names_from_config();
742-
List -> List
743-
end,
744-
case Ret of
756+
Value = case get_forced_feature_flag_names_from_env() of
757+
undefined -> get_forced_feature_flag_names_from_config();
758+
List -> List
759+
end,
760+
case Value of
745761
undefined ->
746-
ok;
762+
Value;
747763
[] ->
748-
?LOG_INFO(
749-
"Feature flags: automatic enablement of feature flags "
750-
"disabled (i.e. none will be enabled automatically)",
751-
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS});
752-
_ ->
753-
?LOG_INFO(
754-
"Feature flags: automatic enablement of feature flags "
755-
"limited to the following list: ~tp",
756-
[Ret],
757-
#{domain => ?RMQLOG_DOMAIN_FEAT_FLAGS})
758-
end,
759-
Ret.
764+
{abs, Value};
765+
[[Op | _] | _] when Op =:= $+ orelse Op =:= $- ->
766+
lists:foldr(
767+
fun
768+
([$+ | NameS], {rel, Plus, Minus}) ->
769+
Name = list_to_atom(NameS),
770+
Plus1 = [Name | Plus],
771+
{rel, Plus1, Minus};
772+
([$- | NameS], {rel, Plus, Minus}) ->
773+
Name = list_to_atom(NameS),
774+
Minus1 = [Name | Minus],
775+
{rel, Plus, Minus1}
776+
end, {rel, [], []}, Value);
777+
_ when is_list(Value) ->
778+
lists:foldr(
779+
fun
780+
(Name, {abs, Abs})
781+
when is_atom(Name) ->
782+
Abs1 = [Name | Abs],
783+
{abs, Abs1};
784+
([C | _] = NameS, {abs, Abs})
785+
when C =/= $+ andalso C =/= $- ->
786+
Name = list_to_atom(NameS),
787+
Abs1 = [Name | Abs],
788+
{abs, Abs1}
789+
end, {abs, []}, Value)
790+
end.
760791

761792
-spec get_forced_feature_flag_names_from_env() -> Ret when
762793
Ret :: FeatureNames | undefined,
763-
FeatureNames :: [rabbit_feature_flags:feature_name()].
794+
FeatureNames :: [rabbit_feature_flags:feature_name() | string()].
764795
%% @private
765796

766797
get_forced_feature_flag_names_from_env() ->
767798
case rabbit_prelaunch:get_context() of
768799
#{forced_feature_flags_on_init := ForcedFFs}
769800
when is_list(ForcedFFs) ->
770801
ForcedFFs;
802+
#{forced_feature_flags_on_init := {'+', List} = ForcedFFs}
803+
when is_list(List) ->
804+
ForcedFFs;
771805
_ ->
772806
undefined
773807
end.
774808

775809
-spec get_forced_feature_flag_names_from_config() -> Ret when
776810
Ret :: FeatureNames | undefined,
777-
FeatureNames :: [rabbit_feature_flags:feature_name()].
811+
FeatureNames :: [rabbit_feature_flags:feature_name() | string()].
778812
%% @private
779813

780814
get_forced_feature_flag_names_from_config() ->
781815
Value = application:get_env(
782816
rabbit, forced_feature_flags_on_init, undefined),
783817
case Value of
784-
undefined ->
785-
Value;
786-
_ when is_list(Value) ->
787-
case lists:all(fun is_atom/1, Value) of
788-
true -> Value;
789-
false -> undefined
790-
end;
791-
_ ->
792-
undefined
818+
undefined -> Value;
819+
_ when is_list(Value) -> Value
793820
end.
794821

795822
-spec sync_cluster_task() -> Ret when

deps/rabbit_common/src/rabbit_env.erl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -999,13 +999,15 @@ forced_feature_flags_on_init(Context) ->
999999
case Value of
10001000
false ->
10011001
%% get_prefixed_env_var() considers an empty string
1002-
%% is the same as an undefined environment variable.
1003-
update_context(Context,
1004-
forced_feature_flags_on_init, undefined, default);
1002+
%% as an undefined environment variable.
1003+
update_context(
1004+
Context,
1005+
forced_feature_flags_on_init, undefined, default);
10051006
_ ->
1006-
Flags = [list_to_atom(V) || V <- string:lexemes(Value, ",")],
1007-
update_context(Context,
1008-
forced_feature_flags_on_init, Flags, environment)
1007+
FeatureNames = string:lexemes(Value, ","),
1008+
update_context(
1009+
Context,
1010+
forced_feature_flags_on_init, FeatureNames, environment)
10091011
end.
10101012

10111013
log_feature_flags_registry(Context) ->

0 commit comments

Comments
 (0)