Skip to content

feat: Adding OpenFeature provider for AWS AppConfig #310

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

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

Conversation

wani-guanxi
Copy link

This PR

Adding new project for AWS AppConfig provider implementation for OpenFeature. This allows to manage feature flags using AWS AppConfig.

  • Provider for AWS AppConfig

Notes

Additional details about the package is in Readme file.

Follow-up Tasks

  • This implementation currently does not support multi-variant AppConfig Feature flags. Or rather there is no way to pass on calling context to the request to AWS AppConfig. I am looking at documentation to figure out how this is done, but haven't got much far on that. Will be looking to add that soon.

How to test

Testing instructions are available in Readme file under Setup section. Thing to note, this will require AWS account to generate access key and ID in order to talk to AWS AppConfig.

@wani-guanxi wani-guanxi requested review from a team as code owners January 18, 2025 15:32
@wani-guanxi wani-guanxi changed the title Feature/appconfig provider feat: Adding OpenFeature provider for AWS AppConfig Jan 18, 2025
@wani-guanxi wani-guanxi force-pushed the feature/appconfig-provider branch from 86985c4 to bf18ec7 Compare January 18, 2025 16:23
…feature#302)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
@beeme1mr
Copy link
Member

Hey @wani-guanxi, sorry for the delay. I'll try and provide feedback in the next few days.

Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
…uteValue format, as supported by AWS app config.

Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
… values

Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
…o be supplied at the time of setup

Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
… in cache

Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Missed updating comments over the course of changes. Fixing that.

Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
Signed-off-by: Ash.Wani <149169001+wani-guanxi@users.noreply.github.com>
@wani-guanxi wani-guanxi force-pushed the feature/appconfig-provider branch from ff6a6ae to c31db95 Compare January 27, 2025 22:55
@beeme1mr beeme1mr assigned beeme1mr, askpt and toddbaert and unassigned markphelps Mar 12, 2025
@beeme1mr
Copy link
Member

Sorry @wani-guanxi, this fell off my radar for a while. I'll try and take a look by the end of the week.

Copy link
Member

@askpt askpt left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution. Just added a couple of comments and suggestions.
1-I noticed there is no try-catch in the entire evaluation and there are a couple of potential exceptions that can happen. Could you please double check if there is no exception being thrown in the evaluation methods?
2-Please make sure to fully use Cancellation Tokens.
3-Check if all the classes need to be exposed and also seal them.

Comment on lines +83 to +84
string pattern = @"^[^:]+:[^:]+(:[^:]+)?$";
var match = Regex.IsMatch(key, pattern);
Copy link
Member

Choose a reason for hiding this comment

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

Could you please investigate using Source Generators for the Regex?

Comment on lines +44 to +48
if (string.IsNullOrEmpty(applicationName))
throw new ArgumentNullException(nameof(applicationName));

if (string.IsNullOrEmpty(environmentName))
throw new ArgumentNullException(nameof(environmentName));
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if it makes sense to throw ProviderFatalException or other provider related exception.

Comment on lines +167 to +169
if(structuredValues == null) return defaultValue;

return structuredValues.TryGetValue(appConfigKey.AttributeKey, out var returnValue) ? returnValue : defaultValue;
Copy link
Member

Choose a reason for hiding this comment

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

We should return extra information (Flag not Found) in case we are resolving using the default flag.

/// <exception cref="AmazonAppConfigDataException">Thrown when there is an error retrieving the configuration from AWS AppConfig.</exception>
private async Task<string> GetFeatureFlagsResponseJson(string configurationProfileId, EvaluationContext context = null)
{
var response = await GetFeatureFlagsStreamAsync(configurationProfileId, context);
Copy link
Member

Choose a reason for hiding this comment

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

Should we make use of the cancellation token here?

ConfigurationProfileIdentifier = configurationProfileId
};

return await _appConfigRetrievalApi.GetLatestConfigurationAsync(profile);
Copy link
Member

Choose a reason for hiding this comment

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

Should we use cancellation token here?

/// <remarks>
/// This method ensures proper cleanup of the memory cache when the instance is disposed.
/// </remarks>
public void Dispose()
Copy link
Member

Choose a reason for hiding this comment

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

I cannot see any IDisposable interface. Is it part of the IRetrievalApi?

/// 4. DateTime
/// 5. String (default fallback)
/// </remarks>
public static class FeatureFlagParser
Copy link
Member

Choose a reason for hiding this comment

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

Should this be private?


<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0;</TargetFrameworks>
<LangVersion>7.3</LangVersion>
Copy link
Member

Choose a reason for hiding this comment

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

Remove this line please.

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0;</TargetFrameworks>
Copy link
Member

Choose a reason for hiding this comment

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

Remove net7.0 and net6.0. Add net9.0 please

<ItemGroup>
<PackageReference Include="AWSSDK.AppCOnfigData" Version="3.7.400.81" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.1" />
<PackageReference Include="Moq" Version="4.20.72" />
Copy link
Member

Choose a reason for hiding this comment

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

Please use NSubstitute instead.

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.

5 participants