-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
add feature-flag client #21091
Merged
Merged
add feature-flag client #21091
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
colesnodgrass
temporarily deployed
to
more-secrets
January 11, 2023 17:32
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 11, 2023 17:32
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 11, 2023 21:44
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 11, 2023 21:45
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 12, 2023 00:33
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 12, 2023 00:33
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 13, 2023 00:02
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 13, 2023 00:02
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 13, 2023 23:04
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 13, 2023 23:05
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 13, 2023 23:28
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 13, 2023 23:28
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 17, 2023 17:02
— with
GitHub Actions
Inactive
colesnodgrass
temporarily deployed
to
more-secrets
January 17, 2023 17:02
— with
GitHub Actions
Inactive
Airbyte Code Coverage
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What
airbyte-featureflag
moduleKotlin
1.8.0How
See the details section below
Todo
flags.yml
should existRecommended reading order
Client.kt
Flags.kt
Context.kt
Factory.kt
Details
There is a lot going on in this PR, I'm going to attempt to break it down into bite-size descriptive chunks below for ease of understanding.
Design
Client
The goal of this feature-flag client is to support both cloud-hosted and non-cloud-hosted configurations.
This has been accomplished by defining a single interface
with multiple implementations;
ConfigFileClient
andLaunchDarklyClient
.To know the current state of a feature-flag, provide a
Flag
object and aContext
object (more information about these concepts in their sections below) to theenabled
method. The returned boolean indicates the current status of theFlag
with theContext
.In order for this
Client
to determine that status of the requestedFlag
andContext
, theConfigFileClient
relies on aflags.yml
configuration file while theLaunchDarklyClient
relies on an external service (LaunchDarkly).As this repo already has some notion of environment based feature-flags, all implementations of the
FeatureFlagClient
will initially support flags managed by environment-variables. The near-term goal is to replace all environment-variables flags withflags.yml
entries and LaunchDarkly flags.This PR contains a Micronaut @Factory for automatically determining which
FeatureFlagClient
should be used. If the application configurationairbyte.feature-flag.path
is defined, theConfigFileClient
will be utilized. Ifairbyte.feature-flag.api-key
is defined, thenLaunchDarklyClient
will be utilized.New
Client
types cannot be defined outside of theairbyte-featureflag
module as theClient
type issealed
with noopen
implementations.Flags
A
Flag
is defined asWhere the
key
is the unique identifier of the flag (must match the name defined in both theflags.yml
and LaunchDarkly). Thedefault
value is the value returned if the flag's state cannot be found or determined. Theteam
is the owning team responsible for managing this feature-flag and only exists for ownership and tracking reasons.There are currently three types of feature flags supported by this client;
Permanent
,Temporary
, andEnvVar
.Permanent
flags are those which will always exist and are not necessarily part of a feature. Presently there is only a single permanent flag which is currently controlled by the env-varLOG_CONNECTOR_MESSAGES
(this should migrate away from being env-var controlled soon after this PR is merged). Permanent flags should extend theFlag
type directlyTemporary
flags will be the majority of feature flags, as these flags will only exist for a finite period of time, being removed entirely once a feature has been completely and successfully released. Temporary flags should extend theTemporary
typeThere is no real difference between a
Permanent
andTemporary
flag other than an indication of the lifecycle intent of the flag itself.EnvVar
flags should only exist for a small period of time as the current env-var based feature-flag solution is replaced with this more well defined and managed solution. More bluntly theEnvVar
class itself will be removed in the near future.EnvVar
flag statuses are determined entirely by the environment-variable they are watching and cannot be changed without restarting the services. EnvVar flags must extend theEnvVar
typeContexts
A
Context
adds additional context to the current request of the status of a feature-flag. For example, the user or workspace that is making the request. As feature-flags may only be enabled for a subset of users or workspaces, this additional information is necessary in order to determine the correct state of the feature-flag being requested.A
Context
is defined asThere are currently two implementations;
User
andWorkspace
.User
represents a user as identified by their unique-id andWorkspace
represents a workspace as identified by its unique-id (and optionally a user-id as well).New
Context
types cannot be defined outside of theairbyte-featureflag
module as theContext
type issealed
with noopen
implementations.flags.yml
The configuration file for determining the status of a feature-flag for non-cloud deployments must be in the format of
Currently flags defined in the
flags.yml
do not respectContexts
. This may be added at a later date.Kotlin
This PR introduces Kotlin to the platform, specifically Kotlin 1.8.0. There has been multiple discussions regarding adding Kotlin into our code base and this new feature-flag client seemed like the opportune time.
Kotlin Features Utilized
There are a number of Kotlin specific features that are utilized within this PR. As this is the first Kotlin PR I'm going to briefly touch on a few of them. If there are any further questions, please reach out to me.
Multiple Types Defined Within a Single File
From Kotlin's coding conventions
This is utilized in nearly every file added in this PR. Technically Java does allow this, but only for sealed classes, which we are already utilizing.
Data Classes
Data classes are similar to Java's record type, but with more flexibility. There are only a few data classes in this PR.
init Blocks
A primary constructor in Kotlin cannot contain any code, init blocks are utilized for these specific purposes.
Internal Visibility
Kotlin supports different visibility modifiers than Java and this PR takes advantage of them; specifically
private
andinternal
. Whereprivate
is only visible within the file its defined in (like these data classes used for parsing the config file) andinternal
is visible to the entire module (like this primary constructor which can only be called from within theairbyte-featureflag
module).Default Parameters, Named Parameters, and @jvmoverloads
Kotlin supports both defaults parameters and named parameters. Both of which reduce the number of methods necessary to support optional parameters or for ensuring that method parameters are passed in a specific order.
For example, the following Kotlin code
can be called from other Kotlin code via
Temporary("key")
orTemporary(default=true, key="key")
. However, as Java does not support default or named parameters, this code has also been annotated with@JvmOverloads
to auto generate the appropriate methods for Java callersObject Types
Kotlin has explicit support for singleton types, called
object
s. These are utilized for defining the feature-flags. When referenced within Kotlin code, they are referenced simply by their object name. However, as Java doesn't have this support natively, anyobject
s referenced from Java code will need to use the object's auto-generated.INSTANCE
; i.e.LogConnectorMessages.INSTANCE
Extension Functions
Kotlin supports extension functions which are utilized a few times in this PR. One adds a Path.onChange function that executes a lambda anytime that Java Path is modified (for watching the
flags.yml
file for changes). The other two add helper methods for converting theContext
type to LaunchDarkly specific contexts. All three of these extension functions are defined with aprivate
visibility and therefore can only be utilized by code within theClient
file.thread Block
Kotlin has a lot of builtin helpers for dealing with common Java patterns. One used in this PR is a
thread
block that creates a background thread for monitoring file changes.