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

feat!: use (and require) OpenFeature SDK v2 #262

Merged
merged 2 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build/Common.props
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
Please sort alphabetically.
Refer to https://docs.microsoft.com/nuget/concepts/package-versioning for semver syntax.
-->
<!-- 1.5-1.9999 -->
<OpenFeatureVer>[1.5,2.0)</OpenFeatureVer>
<!-- 2.0-2.9999 -->
<OpenFeatureVer>[2.0,3.0)</OpenFeatureVer>
Copy link
Member Author

@toddbaert toddbaert Aug 21, 2024

Choose a reason for hiding this comment

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

I've set this to only major version 2 up to 3 (exclusive).

</PropertyGroup>

<ItemGroup Condition="'$(OS)' == 'Unix'">
Expand Down
59 changes: 13 additions & 46 deletions src/OpenFeature.Contrib.Hooks.Otel/MetricsHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using OpenFeature.Model;

Expand Down Expand Up @@ -36,17 +37,8 @@ public MetricsHook()
_evaluationErrorCounter = meter.CreateCounter<long>(MetricsConstants.ErrorTotalName, description: MetricsConstants.ErrorDescription);
}

/// <summary>
/// Executes before the flag evaluation and captures metrics related to the evaluation.
/// The metrics are captured in the following order:
/// 1. The active count is incremented. (feature_flag.evaluation_active_count)
/// 2. The request count is incremented. (feature_flag.evaluation_requests_total)
/// </summary>
/// <typeparam name="T">The type of the flag value.</typeparam>
/// <param name="context">The hook context.</param>
/// <param name="hints">The optional hints.</param>
/// <returns>The evaluation context.</returns>
public override Task<EvaluationContext> Before<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null)
/// <inheritdoc/>
public override ValueTask<EvaluationContext> BeforeAsync<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
var tagList = new TagList
{
Expand All @@ -57,21 +49,12 @@ public override Task<EvaluationContext> Before<T>(HookContext<T> context, IReadO
_evaluationActiveUpDownCounter.Add(1, tagList);
_evaluationRequestCounter.Add(1, tagList);

return base.Before(context, hints);
return base.BeforeAsync(context, hints);
}


/// <summary>
/// Executes after the flag evaluation and captures metrics related to the evaluation.
/// The metrics are captured in the following order:
/// 1. The success count is incremented. (feature_flag.evaluation_success_total)
/// </summary>
/// <typeparam name="T">The type of the flag value.</typeparam>
/// <param name="context">The hook context.</param>
/// <param name="details">The flag evaluation details.</param>
/// <param name="hints">The optional hints.</param>
/// <returns>The evaluation context.</returns>
public override Task After<T>(HookContext<T> context, FlagEvaluationDetails<T> details, IReadOnlyDictionary<string, object> hints = null)
/// <inheritdoc/>
public override ValueTask AfterAsync<T>(HookContext<T> context, FlagEvaluationDetails<T> details, IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
var tagList = new TagList
{
Expand All @@ -83,20 +66,11 @@ public override Task After<T>(HookContext<T> context, FlagEvaluationDetails<T> d

_evaluationSuccessCounter.Add(1, tagList);

return base.After(context, details, hints);
return base.AfterAsync(context, details, hints);
}

/// <summary>
/// Executes when an error occurs during flag evaluation and captures metrics related to the error.
/// The metrics are captured in the following order:
/// 1. The error count is incremented. (feature_flag.evaluation_error_total)
/// </summary>
/// <typeparam name="T">The type of the flag value.</typeparam>
/// <param name="context">The hook context.</param>
/// <param name="error">The exception that occurred.</param>
/// <param name="hints">The optional hints.</param>
/// <returns>The evaluation context.</returns>
public override Task Error<T>(HookContext<T> context, Exception error, IReadOnlyDictionary<string, object> hints = null)
/// <inheritdoc/>
public override ValueTask ErrorAsync<T>(HookContext<T> context, Exception error, IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
var tagList = new TagList
{
Expand All @@ -107,18 +81,11 @@ public override Task Error<T>(HookContext<T> context, Exception error, IReadOnly

_evaluationErrorCounter.Add(1, tagList);

return base.Error(context, error, hints);
return base.ErrorAsync(context, error, hints);
}

/// <summary>
/// Executes after the flag evaluation is complete and captures metrics related to the evaluation.
/// The active count is decremented. (feature_flag.evaluation_active_count)
/// </summary>
/// <typeparam name="T">The type of the flag value.</typeparam>
/// <param name="context">The hook context.</param>
/// <param name="hints">The optional hints.</param>
/// <returns>The evaluation context.</returns>
public override Task Finally<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null)
/// <inheritdoc/>
public override ValueTask FinallyAsync<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
var tagList = new TagList
{
Expand All @@ -128,7 +95,7 @@ public override Task Finally<T>(HookContext<T> context, IReadOnlyDictionary<stri

_evaluationActiveUpDownCounter.Add(-1, tagList);

return base.Finally(context, hints);
return base.FinallyAsync(context, hints);
}
}
}
33 changes: 11 additions & 22 deletions src/OpenFeature.Contrib.Hooks.Otel/OtelHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System;
using System.Threading;

namespace OpenFeature.Contrib.Hooks.Otel

Expand All @@ -16,34 +17,22 @@ public class OtelHook : Hook
{
private readonly TracingHook _tracingHook = new TracingHook();

/// <summary>
/// After is executed after a feature flag has been evaluated.
/// </summary>
/// <param name="context">The hook context</param>
/// <param name="details">The result of the feature flag evaluation</param>
/// <param name="hints">Hints for the feature flag evaluation</param>
/// <returns>An awaitable Task object</returns>
public override Task After<T>(HookContext<T> context, FlagEvaluationDetails<T> details,
IReadOnlyDictionary<string, object> hints = null)
/// <inheritdoc/>
public override ValueTask AfterAsync<T>(HookContext<T> context, FlagEvaluationDetails<T> details,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
_tracingHook.After(context, details, hints);
_tracingHook.AfterAsync(context, details, hints);

return Task.CompletedTask;
return default;
}

/// <summary>
/// Error is executed when an error during a feature flag evaluation occured.
/// </summary>
/// <param name="context">The hook context</param>
/// <param name="error">The exception thrown by feature flag provider</param>
/// <param name="hints">Hints for the feature flag evaluation</param>
/// <returns>An awaitable Task object</returns>
public override Task Error<T>(HookContext<T> context, System.Exception error,
IReadOnlyDictionary<string, object> hints = null)
/// <inheritdoc/>
public override ValueTask ErrorAsync<T>(HookContext<T> context, System.Exception error,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
_tracingHook.Error(context, error, hints);
_tracingHook.ErrorAsync(context, error, hints);

return Task.CompletedTask;
return default;
}

}
Expand Down
4 changes: 2 additions & 2 deletions src/OpenFeature.Contrib.Hooks.Otel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace OpenFeatureTestApp

var client = OpenFeature.Api.Instance.GetClient("my-app");

var val = client.GetBooleanValue("myBoolFlag", false, null);
var val = client.GetBooleanValueAsync("myBoolFlag", false, null);

// Print the value of the 'myBoolFlag' feature flag
System.Console.WriteLine(val.Result.ToString());
Expand Down Expand Up @@ -114,7 +114,7 @@ namespace OpenFeatureTestApp

var client = OpenFeature.Api.Instance.GetClient("my-app");

var val = client.GetBooleanValue("myBoolFlag", false, null);
var val = client.GetBooleanValueAsync("myBoolFlag", false, null);

// Print the value of the 'myBoolFlag' feature flag
System.Console.WriteLine(val.Result.ToString());
Expand Down
29 changes: 9 additions & 20 deletions src/OpenFeature.Contrib.Hooks.Otel/TracingHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using OpenTelemetry.Trace;
using System.Threading;

namespace OpenFeature.Contrib.Hooks.Otel

Expand All @@ -13,15 +14,9 @@ namespace OpenFeature.Contrib.Hooks.Otel
public class TracingHook : Hook
{

/// <summary>
/// After is executed after a feature flag has been evaluated.
/// </summary>
/// <param name="context">The hook context</param>
/// <param name="details">The result of the feature flag evaluation</param>
/// <param name="hints">Hints for the feature flag evaluation</param>
/// <returns>An awaitable Task object</returns>
public override Task After<T>(HookContext<T> context, FlagEvaluationDetails<T> details,
IReadOnlyDictionary<string, object> hints = null)
/// <inheritdoc/>
public override ValueTask AfterAsync<T>(HookContext<T> context, FlagEvaluationDetails<T> details,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
Activity.Current?
.SetTag("feature_flag.key", details.FlagKey)
Expand All @@ -34,22 +29,16 @@ public override Task After<T>(HookContext<T> context, FlagEvaluationDetails<T> d
["feature_flag.provider_name"] = context.ProviderMetadata.Name
}));

return Task.CompletedTask;
return default;
}

/// <summary>
/// Error is executed when an error during a feature flag evaluation occured.
/// </summary>
/// <param name="context">The hook context</param>
/// <param name="error">The exception thrown by feature flag provider</param>
/// <param name="hints">Hints for the feature flag evaluation</param>
/// <returns>An awaitable Task object</returns>
public override Task Error<T>(HookContext<T> context, System.Exception error,
IReadOnlyDictionary<string, object> hints = null)
/// <inheritdoc/>
public override ValueTask ErrorAsync<T>(HookContext<T> context, System.Exception error,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
Activity.Current?.RecordException(error);

return Task.CompletedTask;
return default;
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using ConfigCat.Client;
using ConfigCat.Client.Configuration;
Expand Down Expand Up @@ -35,31 +36,31 @@ public override Metadata GetMetadata()
}

/// <inheritdoc/>
public override Task<ResolutionDetails<bool>> ResolveBooleanValue(string flagKey, bool defaultValue, EvaluationContext context = null)
public override Task<ResolutionDetails<bool>> ResolveBooleanValueAsync(string flagKey, bool defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
return ResolveFlag(flagKey, context, defaultValue);
}

/// <inheritdoc/>
public override Task<ResolutionDetails<string>> ResolveStringValue(string flagKey, string defaultValue, EvaluationContext context = null)
public override Task<ResolutionDetails<string>> ResolveStringValueAsync(string flagKey, string defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
return ResolveFlag(flagKey, context, defaultValue);
}

/// <inheritdoc/>
public override Task<ResolutionDetails<int>> ResolveIntegerValue(string flagKey, int defaultValue, EvaluationContext context = null)
public override Task<ResolutionDetails<int>> ResolveIntegerValueAsync(string flagKey, int defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
return ResolveFlag(flagKey, context, defaultValue);
}

/// <inheritdoc/>
public override Task<ResolutionDetails<double>> ResolveDoubleValue(string flagKey, double defaultValue, EvaluationContext context = null)
public override Task<ResolutionDetails<double>> ResolveDoubleValueAsync(string flagKey, double defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
return ResolveFlag(flagKey, context, defaultValue);
}

/// <inheritdoc/>
public override async Task<ResolutionDetails<Value>> ResolveStructureValue(string flagKey, Value defaultValue, EvaluationContext context = null)
public override async Task<ResolutionDetails<Value>> ResolveStructureValueAsync(string flagKey, Value defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the CancellationToken is captured, we should pass it down to the GetValueDetailsAsync method.

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't want to really make any functional changes here, but this was a very easy one since the ConfigCat SDK already accepted a cancellation token, so I've done this.

{
var user = context?.BuildUser();
var result = await Client.GetValueDetailsAsync(flagKey, defaultValue?.AsObject, user);
Expand Down
2 changes: 1 addition & 1 deletion src/OpenFeature.Contrib.Providers.ConfigCat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ namespace OpenFeatureTestApp

var client = OpenFeature.Api.Instance.GetClient();

var val = client.GetBooleanValue("isMyAwesomeFeatureEnabled", false);
var val = client.GetBooleanValueAsync("isMyAwesomeFeatureEnabled", false);

if(isMyAwesomeFeatureEnabled)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public FeatureManagementProvider(IConfiguration configuration, FeatureManagement
public override Metadata GetMetadata() => metadata;

/// <inheritdoc />
public override async Task<ResolutionDetails<bool>> ResolveBooleanValue(string flagKey, bool defaultValue, EvaluationContext context = null)
public override async Task<ResolutionDetails<bool>> ResolveBooleanValueAsync(string flagKey, bool defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
var variant = await Evaluate(flagKey, context, CancellationToken.None);

Expand All @@ -56,7 +56,7 @@ public override async Task<ResolutionDetails<bool>> ResolveBooleanValue(string f
}

/// <inheritdoc />
public override async Task<ResolutionDetails<double>> ResolveDoubleValue(string flagKey, double defaultValue, EvaluationContext context = null)
public override async Task<ResolutionDetails<double>> ResolveDoubleValueAsync(string flagKey, double defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
var variant = await Evaluate(flagKey, context, CancellationToken.None);

Expand All @@ -67,7 +67,7 @@ public override async Task<ResolutionDetails<double>> ResolveDoubleValue(string
}

/// <inheritdoc />
public override async Task<ResolutionDetails<int>> ResolveIntegerValue(string flagKey, int defaultValue, EvaluationContext context = null)
public override async Task<ResolutionDetails<int>> ResolveIntegerValueAsync(string flagKey, int defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
var variant = await Evaluate(flagKey, context, CancellationToken.None);

Expand All @@ -78,7 +78,7 @@ public override async Task<ResolutionDetails<int>> ResolveIntegerValue(string fl
}

/// <inheritdoc />
public override async Task<ResolutionDetails<string>> ResolveStringValue(string flagKey, string defaultValue, EvaluationContext context = null)
public override async Task<ResolutionDetails<string>> ResolveStringValueAsync(string flagKey, string defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
var variant = await Evaluate(flagKey, context, CancellationToken.None);

Expand All @@ -89,7 +89,7 @@ public override async Task<ResolutionDetails<string>> ResolveStringValue(string
}

/// <inheritdoc />
public override async Task<ResolutionDetails<Value>> ResolveStructureValue(string flagKey, Value defaultValue, EvaluationContext context = null)
public override async Task<ResolutionDetails<Value>> ResolveStructureValueAsync(string flagKey, Value defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
var variant = await Evaluate(flagKey, context, CancellationToken.None);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ namespace OpenFeatureTestApp

var client = OpenFeature.Api.Instance.GetClient();

var val = await client.GetBooleanValue("myBoolFlag", false, null);
var val = await client.GetBooleanValueAsync("myBoolFlag", false, null);

System.Console.WriteLine(val.ToString());
}
Expand Down
Loading