Skip to content

Commit

Permalink
Merge pull request #42 from growthbook/adding-async-variations
Browse files Browse the repository at this point in the history
Added async versions of EvalFeature/GetFeatureValue
  • Loading branch information
Norhaven authored Oct 13, 2024
2 parents ad6d23f + b288af8 commit 6ea94b0
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 8 deletions.
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

0 comments on commit 6ea94b0

Please sign in to comment.