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

Fix #1335: add general-purpose Feature flag system #1390

Merged
merged 20 commits into from
Sep 9, 2024

Conversation

tatu-at-datastax
Copy link
Contributor

@tatu-at-datastax tatu-at-datastax commented Sep 4, 2024

What this PR does:

Adds extensible Feature-Flag system to allow both default, system prop setting, and per-request overrides.

Initially just a single feature is added, "tables":

  • As YAML Config entry: stargate.feature.flags.tables
  • As HTTP header: Feature-Flag-tables (case-insensitive)

That is: when starting; may specific fixed enabled/disabled via application.yaml or system property; latter like:

./mvnw quarkus:dev -Dstargate.jsonapi.operations.database-config.local-datacenter=dc1 \
  -Dquarkus.log.console.darken=2  -Dstargate.feature.flags.tables=true

but if no setting specified (and ONLY in that case), per-request curl header like:

curl -i --location --request POST ... --header 'Feature-Flag-tables: true'

can be used to enable/disable processing

Which issue(s) this PR fixes:
Fixes #1355

Checklist

  • Changes manually tested
  • Automated Tests added/updated
  • Documentation added/updated
  • CLA Signed: DataStax CLA

@tatu-at-datastax tatu-at-datastax changed the title (WIP) Fix #1355: add general-purpose Feature flag system Fix #1355: add general-purpose Feature flag system Sep 5, 2024
@tatu-at-datastax tatu-at-datastax marked this pull request as ready for review September 5, 2024 00:32
@tatu-at-datastax tatu-at-datastax requested a review from a team as a code owner September 5, 2024 00:32
@tatu-at-datastax
Copy link
Contributor Author

Ready for initial review: need to think about how this could be tested better.

}

/**
* Accessor for getting value of given header (case-insensitive), as {@code Boolean} if (and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: does the case insensitivity come from the io.vertx.core.MultiMap ? assuming yes, and that this is because of the HTTP standard, can we make that clear because there is nothing in this code enforcing that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, is due to vertx http server impl that does it for HTTP standard reason.

What I am thinking is that we only document use of lower-case header name for usage, and leave ability for case-insensitivity as impl detail: this since we are not exposing features to actual end users. If case-insensitivity wasn't provided I wouldn't bother actually adding it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmh. While I'd prefer all lower-case, looks like general best practice seems to be mixed case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am on the edge of my seat here, seems to be ??? seems to be...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmmh. Not sure why your GUI showed "seems to be" without second line ("mixed case"). Or is that secret line just shown to me? :-o
(I saw it missing when you screen shared)


private final String featureName;

private final boolean enabledByDefault;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command above says "If no configuration specified (config or request), the feature will be Disabled."

consider: we should prob enforce this by default in the enum and remove the enabledByDefault setting. Concern would be that we end up with a mix of values and it gets confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problem is that precedence is 3-layered:

  1. Explicit value from FeaturesConfig (map keyed by feature)
  2. Explicit value from request header if no (1)
  3. Default if neither (1) or (2).

I originally thought of just leaving (3) to be false for simplicity; I can still do that and drop enabledByDefault as it is not strictly needed -- and can be added if/when needed (or something else that does what is needed).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discussed - drop the enabledByDefault and always default to false. the mental model is these are named boolean values, that default to false.

// First check if there is definition from configuration
Boolean b = fromConfig.get(flag);

if (b == null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I read this correctly, if the feature is disabled in config it is not possible to enable via request. You mention the three ways for controlling features the other day, may be best to spell this out very clearly at the top fo this class.

@@ -25,6 +25,10 @@ stargate:
exception-mappers:
enabled: false

feature: # See io.stargate.sgv2.jsonapi.config.feature.DataApiFeatureConfig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not: can we expand the docs here, or point to expanded docs on the DataApiFeatures class to explain the logic for setting values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed link wrt name, but thinking of documenting only/mostly on code side.

@@ -40,15 +41,21 @@ public final class TestConstants {

// CommandContext for working on the schema objects above

public static final DataApiFeatures DEFAULT_API_FEATURES_FOR_TESTS = DataApiFeatures.empty();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question - how easy / desirable is it to be able to turn on features in a DataApiFeatures class so we can run unit test without needing the things the happen in the DseTestResource class ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am thinking that using DseTestResource reflects actual usage better, and as long as we do not have tons of testing for alternative setting (that is, most tests can use specific default), works for now.

Otherwise we may end up adding test scaffolding that differs from actual running.
This wrt ITs.

Copy link
Contributor

@amorton amorton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally like where this is going, just comments on names and some details.

@tatu-at-datastax
Copy link
Contributor Author

Ok: situation at the end of week:

  1. Things work wrt Config, Header overrides, with manual testing
  2. Addressed doc/comment suggestions
  3. Figured out how to do ITs, to verify same as (1)
  4. Ran out of time to address one last major thing ("I really want to get the DataApiRequestInfo onto the CommandContext and remove the dependency injection. ") -- hoping to check that on monday.
  5. Aside from (4), ready for re-review!

Copy link
Collaborator

@vkarpov15 vkarpov15 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@amorton
Copy link
Contributor

amorton commented Sep 9, 2024

reviewed in person, Done for me . Will approve, and then we need to get the error object V2 flag to use features config

Copy link
Contributor

@amorton amorton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved, see last comment

@tatu-at-datastax
Copy link
Contributor Author

Last changes; will merge once CI passes.

@tatu-at-datastax tatu-at-datastax merged commit d345c78 into main Sep 9, 2024
3 checks passed
@tatu-at-datastax tatu-at-datastax deleted the tatu/1335-feature-flags branch September 9, 2024 20:26
@tatu-at-datastax tatu-at-datastax changed the title Fix #1355: add general-purpose Feature flag system Fix #1335: add general-purpose Feature flag system Sep 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants