Skip to content

Commit 9f2216e

Browse files
committed
Deprecated features: New module to manage deprecated features (!)
This introduces a way to declare deprecated features in the code, not only in our communication. The new module allows to disallow the use of a deprecated feature and/or warn the user when he relies on such a feature. [Why] Currently, we only tell people about deprecated features through blog posts and the mailing-list. This might be insufficiant for our users that a feature they use will be removed in a future version: * They may not read our blog or mailing-list * They may not understand that they use such a deprecated feature * They might wait for the big removal before they plan testing * They might not take it seriously enough The idea behind this patch is to increase the chance that users notice that they are using something which is about to be dropped from RabbitMQ. Anopther benefit is that they should be able to test how RabbitMQ will behave in the future before the actual removal. This should allow them to test and plan changes. [How] When a feature is deprecated in other large projects (such as FreeBSD where I took the idea from), it goes through a lifecycle: 1. The feature is still available, but users get a warning somehow when they use it. They can disable it to test. 2. The feature is still available, but disabled out-of-the-box. Users can re-enable it (and get a warning). 3. The feature is disconnected from the build. Therefore, the code behind it is still there, but users have to recompile the thing to be able to use it. 4. The feature is removed from the source code. Users have to adapt or they can't upgrade anymore. The solution in this patch offers the same lifecycle. A deprecated feature will be in one of these deprecation phases: 1. `optout`: The feature is available. Users get a warning if they use it. They can disable it from the configuration. 2. `optin`: The feature is available but disabled by default. Users get an error if they use it and RabbitMQ behaves like the feature is removed. They can re-enable is from the configuration and get a warning. 3. `disconnected`: The feature is present in the source code, but is disabled and can't be re-enabled without recompiling RabbitMQ. Users get the same behavior as if the code was removed. 4. `removed`: The feature's code is gone. The whole thing is based on the feature flags subsystem, but it has the following differences with other feature flags: * The semantic is reversed: the feature flag behind a deprecated feature is disabled when the deprecated feature is permitted, or enabled when the deprecated feature is denied. * The feature flag behind a deprecated feature is enabled out-of-the-box (meaning the deprecated feature is denied): * if the deprecation phase is `optout` and the configuration denies the deprecated feature * if the deprecation phase is `optin` and the configuration doesn't permit the deprecated feature * if the deprecation phase is `disconnected` or `removed` * Feature flags behind deprecated feature don't appear in feature flags listings. Otherwise, deprecated features' feature flags are managed like other feature flags, in particular inside clusters. To declare a deprecated feature: -rabbit_deprecated_feature( {my_deprecated_feature, #{deprecation_phase => optout, warning => "This feature will be removed in RabbitMQ X.0" }}). Then, to check the state of a deprecated feature in the code: case rabbit_deprecated_features:is_permitted(my_deprecated_feature) of true -> %% The deprecated feature is still permitted. ok; false -> %% The deprecated feature is gone or should be considered %% unavailable. error end. Warnings and errors are logged automatically. A message is generated automatically, but it is possible to define a message in the deprecated feature flag declaration like in the example above. Here is an example of a logged warning that was generated automatically: 2023-03-01 12:23:29.627795+01:00 [warning] <12086.105.0> Deprecated features: `my_deprecated_feature`: Feature `my_deprecated_feature` is deprecated; it is enabled by default, except if configured otherwise To override the default state of `optout` and `optin` deprecation phases, users can set the following configuration: # In rabbitmq.conf: permit_deprecated_features.my_deprecated_feature = true # or false The actual behavior protected by a deprecated feature check is out of scope for this subsystem. It is the repsonsibility of each deprecated feature code to determine what to do when the deprecated feature is denied.
1 parent 926466f commit 9f2216e

12 files changed

+1167
-153
lines changed

deps/rabbit/BUILD.bazel

+8
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,14 @@ rabbitmq_integration_suite(
379379
size = "medium",
380380
)
381381

382+
rabbitmq_integration_suite(
383+
name = "deprecated_features_SUITE",
384+
size = "medium",
385+
additional_beam = [
386+
":feature_flags_v2_SUITE_beam_files",
387+
],
388+
)
389+
382390
rabbitmq_integration_suite(
383391
name = "disconnect_detected_during_alarm_SUITE",
384392
size = "medium",

deps/rabbit/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ ct-slow: CT_SUITES = $(SLOW_CT_SUITES)
241241
# --------------------------------------------------------------------
242242

243243
RMQ_ERLC_OPTS += -I $(DEPS_DIR)/rabbit_common/include
244-
EDOC_OPTS += {preprocess,true}
244+
EDOC_OPTS += {preprocess,true},{includes,["."]}
245245

246246
ifdef INSTRUMENT_FOR_QC
247247
RMQ_ERLC_OPTS += -DINSTR_MOD=gm_qc

deps/rabbit/docs/rabbitmq.conf.example

+19
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,25 @@
548548
## NB: Change these only if you understand what you are doing!
549549
##
550550

551+
## To permit or deny a deprecated feature when it is in its `optout` or
552+
## `optin` deprecation phase, the default state can be overriden from the
553+
## configuration.
554+
##
555+
## When a deprecated feature is "opt-out" (first phase of the deprecation
556+
## period), it means the feature is available by default and can be turned off by
557+
## setting it to false in the configuration.
558+
##
559+
## When a deprecated feature is "opt-in" (second phase of the deprecation
560+
## period), it menas the feature is unavailable by default but can be turned back
561+
## on by setting it to true in the configuration.
562+
##
563+
## When a deprecated feature is "disconnected" or "removed" (last two phases of
564+
## the deprecation period), it is no longer possible to turn it back on from the
565+
## configuration.
566+
##
567+
# permit_deprecated_features.a_deprecated_feature = true
568+
# permit_deprecated_features.another_deprecated_feature = false
569+
551570
## Timeout used when waiting for Mnesia tables in a cluster to
552571
## become available.
553572
##

deps/rabbit/priv/schema/rabbit.schema

+25
Original file line numberDiff line numberDiff line change
@@ -2088,6 +2088,31 @@ end}.
20882088
{datatype, integer}
20892089
]}.
20902090

2091+
%%
2092+
%% Feature flags and deprecated features
2093+
%% =====================================
2094+
%%
2095+
2096+
{mapping,
2097+
"permit_deprecated_features.$name", "rabbit.permit_deprecated_features",
2098+
[{datatype, {enum, [true, false]}}]
2099+
}.
2100+
2101+
%% This converts:
2102+
%% permit_deprecated_features.my_feature = true
2103+
%% to:
2104+
%% {rabbit, [{permit_deprecated_features, #{my_feature => true}}]}.
2105+
2106+
{translation, "rabbit.permit_deprecated_features",
2107+
fun(Conf) ->
2108+
Settings = cuttlefish_variable:filter_by_prefix(
2109+
"permit_deprecated_features", Conf),
2110+
maps:from_list(
2111+
[{list_to_atom(FeatureName), State}
2112+
|| {["permit_deprecated_features", FeatureName], State}
2113+
<- Settings])
2114+
end}.
2115+
20912116
% ==========================
20922117
% Kernel section
20932118
% ==========================

0 commit comments

Comments
 (0)