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

Refactor FeatureFlags #17611

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

finnegancarroll
Copy link
Contributor

@finnegancarroll finnegancarroll commented Mar 17, 2025

Description

There are a handful of competing ways to set feature flags today.

  1. FeatureFlags.initializeFeatureFlags
    Takes a setting object and overwrites FeatureFlags.settings. Node invokes this to set flags on startup, but it is also used throughout unit tests to dynamically update and clear feature flags. Provides no way to set a single flag without rewriting all settings.

  2. System.setProperty:
    Sets the feature flag as a JVM property. Calls to FeatureFlags.isEnabled() will check System.getProperty() and see this flag. Allows dynamic setting of individual feature flags.

  3. FeatureFlagSetter.set:
    A small wrapper around the above System.setProperty() which additionally tracks which flags it sets. Used only in tests. Tracks set properties and exposes clearAll() to unset all tracked properties which is invoked during OpenSearchTestCase teardown to ensure a "clean slate" for each test.

Together these implementations provide the desired functionality for feature flags across test and non-test use cases but present some issues:

  • Non of the implementations are thread safe as feature flags are global/static and may be modified at any time.
  • System properties persist for the lifetime of the JVM and can carry over to other tests run on the same JVM, polluting other test environments if not cleared.
  • System.getProperty() can be slow and have performance implications when feature flags are retrieved in a hot path.
  • When not using System.setProperty(), clearing or setting any single feature flag resets all flags.

This PR refactors FeatureFlags to consolidate feature flag functionality and remove usage of JVM system properties in all cases except initializeFeatureFlags which is called once by Node on startup.

Specific changes include:

  • Replaces FeatureFlags immutable internal settings with a map.
  • initializeFeatureFlags now reads and sets feature flags from JVM system properties.
  • isEnabled no longer checks JVM system properties to mitigate performance impact.
  • For test use cases functionality for setting/unsetting flags is provided behind FeatureFlags.TestUtils for clarity.
    • @LockFeatureFlag annotation provided as a thread safe way to set a feature flag for the duration of the test case.
    • FeatureFlags.TestUtils.with for thread safe execution of a critical section with provided feature flag enabled.
    • FeatureFlags.TestUtils.FlagLock for directly accessing a feature flag's lock.

Related Issues

Resolves #16519

Check List

  • Functionality includes testing.
  • API changes companion pull request created, if applicable.
  • Public documentation issue/PR created, if applicable.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@github-actions github-actions bot added bug Something isn't working good first issue Good for newcomers Search Search query, autocomplete ...etc v3.0.0 Issues and PRs related to version 3.0.0 labels Mar 17, 2025
Copy link
Contributor

❌ Gradle check result for fdec16b: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@finnegancarroll finnegancarroll force-pushed the feature-flag-kinda-slow branch from fdec16b to f1d5490 Compare March 17, 2025 19:25
Copy link
Contributor

❌ Gradle check result for f1d5490: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@finnegancarroll finnegancarroll force-pushed the feature-flag-kinda-slow branch from f1d5490 to 1228bda Compare March 17, 2025 19:44
Copy link
Contributor

❌ Gradle check result for 1228bda: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@finnegancarroll finnegancarroll force-pushed the feature-flag-kinda-slow branch from 1228bda to b688424 Compare March 17, 2025 20:06
Copy link
Contributor

❌ Gradle check result for 4a3e60f: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@finnegancarroll
Copy link
Contributor Author

Verifying isEnabled is represented less in big5 term flame graph per #16519.

Feature branch:
image

Main branch:
image

- Remove internal immutable `settings` in favor of `ConcurrentHashMap`.
- Move functionality to internal `FeatureFlagsImpl` class.
Expose public api of `FeatureFlagsImpl` in FeatureFlags.
Expose test api of `FeatureFlagsImpl` in FeatureFlags.TestUtils.
- Read and set JVM system properties once on `initializeFeatureFlags`.
Remove JVM system properties check from `isEnabled`.
- Add `FlagLock` in `TestUtils` to maintain a lock for each feature flag.
- Add helper functions to set & access feature flags in a thread safe way.
`TestUtils.with(<feature flag>, () -> {})` to execute crtical sections.
`New FlagLock(<feature flag>)` for fine grained control.

Signed-off-by: Finn Carroll <[email protected]>
- Add annotation in OpenSearchTestCase to enable and lock a flag for the
duration of a single test case.

Signed-off-by: Finn Carroll <[email protected]>
- Add cases for public api.
- Add cases for thread safe helpers
@LockFeatureFlag
FlagLock
TestUtils.with

Signed-off-by: Finn Carroll <[email protected]>
Signed-off-by: Finn Carroll <[email protected]>
Replace all usages of `FeatureFlagSetter` in tests.
Replace all usages of JVM system properties for feature flags in tests.
Replace all usages of `initializeFeatureFlags` with `TestUtils.set` in tests.

Signed-off-by: Finn Carroll <[email protected]>
@finnegancarroll finnegancarroll force-pushed the feature-flag-kinda-slow branch from 4a3e60f to 4bc33cd Compare March 18, 2025 20:37
Copy link
Contributor

❌ Gradle check result for 4bc33cd: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

Signed-off-by: Finn Carroll <[email protected]>
@finnegancarroll finnegancarroll force-pushed the feature-flag-kinda-slow branch from 4bc33cd to 94fd7af Compare March 18, 2025 21:06
Copy link
Contributor

❌ Gradle check result for 94fd7af: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

- Add missing LockFeatureFlag annotations.
- Cannot use annotation in tests which expect exception thrown.
- SEARCHABLE_SNAPSHOT_EXTENDED_COMPATIBILITY has no setting? Adding.
- Flight server tests need flag enabled on setup.

Signed-off-by: Finn Carroll <[email protected]>
@finnegancarroll finnegancarroll force-pushed the feature-flag-kinda-slow branch from feec9a7 to e8ad6be Compare March 18, 2025 21:52
Copy link
Contributor

❌ Gradle check result for e8ad6be: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@finnegancarroll finnegancarroll changed the title Refactor feature flags for better test support Refactor FeatureFlags Mar 18, 2025
@finnegancarroll
Copy link
Contributor Author

{"run-benchmark-test": "id_5"}

Copy link
Contributor

The Jenkins job url is https://build.ci.opensearch.org/job/benchmark-pull-request/2624/ . Final results will be published once the job is completed.

@finnegancarroll
Copy link
Contributor Author

{"run-benchmark-test": "id_3"}

Copy link
Contributor

✅ Gradle check result for e8ad6be: SUCCESS

Copy link

codecov bot commented Mar 20, 2025

Codecov Report

Attention: Patch coverage is 95.12195% with 4 lines in your changes missing coverage. Please review.

Project coverage is 72.37%. Comparing base (1166998) to head (e8ad6be).
Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
.../java/org/opensearch/common/util/FeatureFlags.java 95.12% 4 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #17611      +/-   ##
============================================
- Coverage     72.48%   72.37%   -0.11%     
+ Complexity    65771    65694      -77     
============================================
  Files          5311     5311              
  Lines        304973   305063      +90     
  Branches      44229    44241      +12     
============================================
- Hits         221045   220799     -246     
- Misses        65830    66221     +391     
+ Partials      18098    18043      -55     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@finnegancarroll
Copy link
Contributor Author

distance_amount_agg is just barely showing a ~5% regression in 90+ percentile latency.
#17611 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good first issue Good for newcomers Search Search query, autocomplete ...etc v3.0.0 Issues and PRs related to version 3.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] FeatureFlags.isEnabled is kinda slow
3 participants