Skip to content

Commit f79da34

Browse files
committed
Spike: Fractional evaluation in clients
1 parent 362e2c4 commit f79da34

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

src/Octopus.OpenFeature.Provider/Octopus.OpenFeature.Provider.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<ItemGroup>
2727
<PackageReference Include="OpenFeature" Version="2.11.1" />
2828
<PackageReference Include="System.Text.Json" Version="9.0.12" />
29+
<PackageReference Include="murmurhash" Version="1.0.3" />
2930
</ItemGroup>
3031

3132
<ItemGroup>

src/Octopus.OpenFeature.Provider/OctopusFeatureClient.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@ public class FeatureToggles(FeatureToggleEvaluation[] evaluations, byte[] conten
1212
public byte[] ContentHash { get; } = contentHash;
1313
}
1414

15-
public class FeatureToggleEvaluation(string name, string slug, bool isEnabled, KeyValuePair<string, string>[] segments)
15+
public class FeatureToggleEvaluation(string name, string slug, bool isEnabled, string evaluationKey, KeyValuePair<string, string>[] segments, int percentage)
1616
{
1717
public string Name { get; } = name;
1818

1919
public string Slug { get; } = slug;
2020

2121
public bool IsEnabled { get; } = isEnabled;
2222

23+
public string EvaluationKey { get; } = evaluationKey;
24+
2325
public KeyValuePair<string, string>[] Segments { get; } = segments;
26+
27+
public int Percentage { get; } = percentage;
2428
}
2529

2630
interface IOctopusFeatureClient

src/Octopus.OpenFeature.Provider/OctopusFeatureContext.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using System.Text.RegularExpressions;
1+
using System.Text;
2+
using System.Text.RegularExpressions;
23
using Microsoft.Extensions.Logging;
4+
using Murmur;
35
using OpenFeature.Constant;
46
using OpenFeature.Model;
57

@@ -64,6 +66,23 @@ bool MatchesSegment(EvaluationContext? context, IEnumerable<KeyValuePair<string,
6466
bool Evaluate(FeatureToggleEvaluation evaluation, EvaluationContext? context = null)
6567
{
6668
return evaluation.IsEnabled &&
69+
(evaluation.Percentage == 100 || context?.TargetingKey is not null && GetNormalizedNumber(evaluation.EvaluationKey, context.TargetingKey) < evaluation.Percentage) &&
6770
(evaluation.Segments.Length == 0 || MatchesSegment(context, evaluation.Segments));
6871
}
72+
73+
/// <summary>
74+
/// Produces a normalized number between 0 and 100 for a given TargetingKey, with less than 1% variance
75+
/// </summary>
76+
private int GetNormalizedNumber(string evaluationKey, string targetingKey)
77+
{
78+
const int one = 1;
79+
const string separator = ":";
80+
81+
var bytes = Encoding.UTF8.GetBytes(string.Concat(evaluationKey, separator, targetingKey));
82+
83+
using var algorithm = MurmurHash.Create32();
84+
var hash = algorithm.ComputeHash(bytes);
85+
var value = BitConverter.ToUInt32(hash, 0);
86+
return (int)(value % 100 + one);
87+
}
6988
}

0 commit comments

Comments
 (0)