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

Added async versions of EvalFeature/GetFeatureValue #42

Merged
merged 1 commit into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.7]

- Added async versions of EvalFeature/GetFeatureValue and a flag on the originals for backwards compatibility.

## [1.0.6]

- Set hash version with rule
Expand Down
40 changes: 36 additions & 4 deletions GrowthBook/GrowthBook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,24 @@ public bool IsOff(string key)
}

/// <inheritdoc />
public T GetFeatureValue<T>(string key, T fallback)
public T GetFeatureValue<T>(string key, T fallback, bool alwaysLoadFeatures = false)
{
var value = EvalFeature(key).Value;
if (alwaysLoadFeatures)
{
LoadFeatures().Wait();
}

var result = EvaluateFeature(key);
var value = result.Value;

return value.IsNull() ? fallback : value.ToObject<T>();
}

/// <inheritdoc />
public async Task<T> GetFeatureValueAsync<T>(string key, T fallback, CancellationToken? cancellationToken = null)
{
var result = await EvalFeatureAsync(key, cancellationToken);
var value = result.Value;

return value.IsNull() ? fallback : value.ToObject<T>();
}
Expand All @@ -187,8 +202,25 @@ public Action Subscribe(Action<Experiment, ExperimentResult> callback)
}

/// <inheritdoc />
public FeatureResult EvalFeature(string featureId)
public FeatureResult EvalFeature(string featureId, bool alwaysLoadFeatures = false)
{
if (alwaysLoadFeatures)
{
LoadFeatures().Wait();
}

return EvaluateFeature(featureId);
}

public async Task<FeatureResult> EvalFeatureAsync(string featureId, CancellationToken? cancellationToken = null)
{
await LoadFeatures(cancellationToken: cancellationToken);

return EvaluateFeature(featureId);
}

private FeatureResult EvaluateFeature(string featureId)
{
try
{
if (!Features.TryGetValue(featureId, out Feature feature))
Expand Down Expand Up @@ -288,7 +320,7 @@ public ExperimentResult Run(Experiment experiment)

return result;
}
catch(Exception ex)
catch (Exception ex)
{
_logger.LogError(ex, $"Encountered an unhandled exception while executing '{nameof(Run)}'");

Expand Down
2 changes: 1 addition & 1 deletion GrowthBook/GrowthBook.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<RepositoryUrl>https://github.com/growthbook/growthbook-csharp.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>GrowthBook,A/B test,feature toggle,flag</PackageTags>
<Version>1.0.6</Version>
<Version>1.0.7</Version>
<Title>GrowthBook C# SDK</Title>
<PackageProjectUrl>https://www.growthbook.io/</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down
34 changes: 31 additions & 3 deletions GrowthBook/IGrowthBook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,28 @@ public interface IGrowthBook : IDisposable
bool IsOff(string key);

/// <summary>
/// Gets the value of a feature cast to the specified type.
/// Gets the value of a feature cast to the specified type. This is a blocking operation and should not be used from a UI thread.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key">The feature key.</param>
/// <param name="fallback">Fallback value to return if the feature is not on.</param>
/// <param name="alwaysLoadFeatures">
/// Loads all features from the repository/cache prior to executing.
/// This is included for backwards compatibility and, when set to true, becomes a blocking operation and should not be used from a UI thread.
/// If possible, please use the async version of this method: <see cref="GetFeatureValueAsync{T}(string, T, CancellationToken?)"/>
/// </param>
/// <returns>Value of a feature cast to the specified type.</returns>
T GetFeatureValue<T>(string key, T fallback);
T GetFeatureValue<T>(string key, T fallback, bool alwaysLoadFeatures = false);

/// <summary>
/// Asynchronously gets the value of a feature cast to the specified type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key">The feature key.</param>
/// <param name="fallback">Fallback value to return if the feature is not on.</param>
/// <param name="cancellationToken">The cancellation token for this operation.</param>
/// <returns>Value of a feature cast to the specified type.</returns>
Task<T> GetFeatureValueAsync<T>(string key, T fallback, CancellationToken? cancellationToken = null);

/// <summary>
/// Returns a map of the latest results indexed by experiment key.
Expand All @@ -51,8 +66,21 @@ public interface IGrowthBook : IDisposable
/// Evaluates a feature and returns a feature result.
/// </summary>
/// <param name="key">The feature key.</param>
/// <param name="alwaysLoadFeatures">
/// Loads all features from the feature repository/cache prior to executing.
/// This is included for backwards compatibility and, when set to true, becomes a blocking operation and should not be used from a UI thread.
/// If possible, please use the async version of this method: <see cref="EvalFeatureAsync(string, CancellationToken?)"/>
/// </param>
/// <returns>The feature result.</returns>
FeatureResult EvalFeature(string key, bool alwaysLoadFeatures = false);

/// <summary>
/// Asynchronously loads and evaluates a feature and returns a feature result.
/// </summary>
/// <param name="featureId">The feature ID.</param>
/// <param name="cancellationToken">The cancellation token for the operation.</param>
/// <returns>The feature result.</returns>
FeatureResult EvalFeature(string key);
Task<FeatureResult> EvalFeatureAsync(string featureId, CancellationToken? cancellationToken = null);

/// <summary>
/// Evaluates an experiment and returns an experiment result.
Expand Down
Loading