-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
🪟 🔧 Handle LD feature flags besides featureService.overwrites
#19773
🪟 🔧 Handle LD feature flags besides featureService.overwrites
#19773
Conversation
I like the idea of having a better mechanism to treat those as individual flags. Two notes before you go too deep into finalizing this yet:
|
That's a pair of very good points, @timroes, thank you.
// enable feature from LD
{ overwrite: true }
// disable feature from LD
{ overwrite: false }
// no override; default variation
{} |
f76d471
to
257f776
Compare
257f776
to
374291e
Compare
featureService.overwrites
featureService.overwrites
The purpose of the value and the contextual meaning of `true` and `false` just read more easily with this phrasing.
374291e
to
d3d5441
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice work @ambirdsall! This is a solid improvement to working with feature service overwrites 👏🏻 I tested locally with the data geography & cron sync mode flags, and everything worked as expected. I also checked the LD flags on production, and the targeting for ThriveCap on featureService.ALLOW_SYNC_SUB_ONE_HOUR_CRON_EXPRESSIONS
looks good.
The only thought I had while reading through - and this is definitely out of scope for this PR - is why do we have different semantics for "experiments" and the "featureService" flags? Experiments
uses keys of an interface while FeatureItem
uses an enum, experiments uses an rxjs observable while featureService overwrites use a callback function, experiments are camelCase while featureService is ALL_CAPS. Anyway, not pertinent to the core changes here, just strikes me as strangely inconsistent.
* |--------------------------+-----------------------------------------------| | ||
* | `{}` | use the application's default feature setting | | ||
* | `{ "enabled": true }` | enable the feature | | ||
* | `{ "enabled": false }` | disable the feature | | ||
* |--------------------------+-----------------------------------------------| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought, not a necessary blocker for this PR: Would it maybe be nicer if we'd use a string
for the tristate, that can either be empty, "true"
or "false"
? That would be easier to type in LD and would have the benefit, that the default value for string experiments already is the empty string, while using the JSON flag here, we'll require to type {}
for each of the new features to not break the code below that destructures the object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While it would save us a bit of typing, I found the slightly more verbose JSON definitions to be a bit more readable in the devtools network tab. To minimize the hassle of creating new flags, I made sure they can be copy-pasted verbatim from the new documentation in Notion.
That said, "enabled" | "disabled" | ""
would have been a very clean type signature ¯\_(ツ)_/¯
Background
Feature flags in LaunchDarkly serve multiple uses in airbyte cloud at various points in the lifecycle of a feature release. Sometimes they are used to opt specific people into the feature for testing; sometimes they are used to "soft launch" a feature in a way that can be rolled out and rolled back without the lag of a code update and deployment; sometimes they are used to grandfather certain users into the ability to continue using otherwise deprecated code.
The original implementation of our LaunchDarkly frontend integration put all feature toggles into a single LD "feature flag", with various experiences defined as variants on that single flag. Because all of a given flag's variants are mutually exclusive to a given user, this means we could not independently toggle different features for the whole userbase without auditing and possibly editing every other more targeted rule and worrying about rule precedence in LD. This added complexity and hassle scales up exponentially with the number of distinct feature toggles in use at a given moment.
External context
A chunk of the work for this feature happened in LaunchDarkly itself: for each feature toogle that has been managed to date with the shared
featureService.overwrites
feature flag needed to be ported to a new feature flag using an{ enabled?: boolean }
payload, along with all targeting rules used to apply that variant. More on this below.What this changes
This adds logic to the LaunchDarkly integration that populates the FeatureService's overwrites to accept single-toggle feature flags. It hardcodes the assumption that all such flags will use a key that begins with the same
featureService.
prefix as the shared feature flag: this (otherwise arbitrary) criterion lets us quickly and reliably filter the list of feature flags in LD to the set that is specifically relevant to the frontend codebase for visibility and auditing. Closes #19726.Here's a recording of a manual test of the new code, toggling the presence of two different sub-nav link via new, independent feature flags. At the time of recording this screencap, #20105 had not yet been merged into the feature branch, which is kind of ideal for demonstration purposes: explicitly using the "enable feature" and "disable feature" variants work identically for each feature, while using the "use application default" variants enables the "Data residency" link and disables the "dbt Cloud integration" one, using the cloud build's default features as of commit
7b19f59
:🚨 User Impact 🚨
Existing feature flags are handled exactly as before, so there should be zero user impact. There is one cohort of users who have been grandfathered into continued use of sub-one-hour sync scheduling, so some care should be taken to ensure that deploying this change causes no interruption to that targeting logic.
Manual testing
Unfortunately, there's not a great way to add automated tests for this feature: writing jest tests would require lots of time consuming effort to mock out large swaths of the application context before any assertions can be written; cypress tests would be ideal, but we only use
LDExperimentService
in cloud, and we don't yet have a test suite for that. So manual testing it is.Tests done:
featureService.overwrites
feature flag does not affect the UI (same testing setup)Documentation
This seems worth documenting for the Airbyte team! That is not, strictly speaking, a concern for this PR, since it happens outside of the codebase; just calling it out to keep myself honest.