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

fix: deadlocks in client applications #150

Merged
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
40 changes: 20 additions & 20 deletions src/OpenFeature/OpenFeatureClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,63 +107,63 @@ public FeatureClient(string name, string version, ILogger logger = null, Evaluat
/// <inheritdoc />
public async Task<bool> GetBooleanValue(string flagKey, bool defaultValue, EvaluationContext context = null,
FlagEvaluationOptions config = null) =>
(await this.GetBooleanDetails(flagKey, defaultValue, context, config)).Value;
(await this.GetBooleanDetails(flagKey, defaultValue, context, config).ConfigureAwait(false)).Value;

/// <inheritdoc />
public async Task<FlagEvaluationDetails<bool>> GetBooleanDetails(string flagKey, bool defaultValue,
EvaluationContext context = null, FlagEvaluationOptions config = null) =>
await this.EvaluateFlag(this.ExtractProvider<bool>(provider => provider.ResolveBooleanValue),
FlagValueType.Boolean, flagKey,
defaultValue, context, config);
defaultValue, context, config).ConfigureAwait(false);

/// <inheritdoc />
public async Task<string> GetStringValue(string flagKey, string defaultValue, EvaluationContext context = null,
FlagEvaluationOptions config = null) =>
(await this.GetStringDetails(flagKey, defaultValue, context, config)).Value;
(await this.GetStringDetails(flagKey, defaultValue, context, config).ConfigureAwait(false)).Value;

/// <inheritdoc />
public async Task<FlagEvaluationDetails<string>> GetStringDetails(string flagKey, string defaultValue,
EvaluationContext context = null, FlagEvaluationOptions config = null) =>
await this.EvaluateFlag(this.ExtractProvider<string>(provider => provider.ResolveStringValue),
FlagValueType.String, flagKey,
defaultValue, context, config);
defaultValue, context, config).ConfigureAwait(false);

/// <inheritdoc />
public async Task<int> GetIntegerValue(string flagKey, int defaultValue, EvaluationContext context = null,
FlagEvaluationOptions config = null) =>
(await this.GetIntegerDetails(flagKey, defaultValue, context, config)).Value;
(await this.GetIntegerDetails(flagKey, defaultValue, context, config).ConfigureAwait(false)).Value;

/// <inheritdoc />
public async Task<FlagEvaluationDetails<int>> GetIntegerDetails(string flagKey, int defaultValue,
EvaluationContext context = null, FlagEvaluationOptions config = null) =>
await this.EvaluateFlag(this.ExtractProvider<int>(provider => provider.ResolveIntegerValue),
FlagValueType.Number, flagKey,
defaultValue, context, config);
defaultValue, context, config).ConfigureAwait(false);

/// <inheritdoc />
public async Task<double> GetDoubleValue(string flagKey, double defaultValue,
EvaluationContext context = null,
FlagEvaluationOptions config = null) =>
(await this.GetDoubleDetails(flagKey, defaultValue, context, config)).Value;
(await this.GetDoubleDetails(flagKey, defaultValue, context, config).ConfigureAwait(false)).Value;

/// <inheritdoc />
public async Task<FlagEvaluationDetails<double>> GetDoubleDetails(string flagKey, double defaultValue,
EvaluationContext context = null, FlagEvaluationOptions config = null) =>
await this.EvaluateFlag(this.ExtractProvider<double>(provider => provider.ResolveDoubleValue),
FlagValueType.Number, flagKey,
defaultValue, context, config);
defaultValue, context, config).ConfigureAwait(false);

/// <inheritdoc />
public async Task<Value> GetObjectValue(string flagKey, Value defaultValue, EvaluationContext context = null,
FlagEvaluationOptions config = null) =>
(await this.GetObjectDetails(flagKey, defaultValue, context, config)).Value;
(await this.GetObjectDetails(flagKey, defaultValue, context, config).ConfigureAwait(false)).Value;

/// <inheritdoc />
public async Task<FlagEvaluationDetails<Value>> GetObjectDetails(string flagKey, Value defaultValue,
EvaluationContext context = null, FlagEvaluationOptions config = null) =>
await this.EvaluateFlag(this.ExtractProvider<Value>(provider => provider.ResolveStructureValue),
FlagValueType.Object, flagKey,
defaultValue, context, config);
defaultValue, context, config).ConfigureAwait(false);

private async Task<FlagEvaluationDetails<T>> EvaluateFlag<T>(
(Func<string, T, EvaluationContext, Task<ResolutionDetails<T>>>, FeatureProvider) providerInfo,
Expand Down Expand Up @@ -211,32 +211,32 @@ private async Task<FlagEvaluationDetails<T>> EvaluateFlag<T>(
FlagEvaluationDetails<T> evaluation;
try
{
var contextFromHooks = await this.TriggerBeforeHooks(allHooks, hookContext, options);
var contextFromHooks = await this.TriggerBeforeHooks(allHooks, hookContext, options).ConfigureAwait(false);

evaluation =
(await resolveValueDelegate.Invoke(flagKey, defaultValue, contextFromHooks.EvaluationContext))
(await resolveValueDelegate.Invoke(flagKey, defaultValue, contextFromHooks.EvaluationContext).ConfigureAwait(false))
.ToFlagEvaluationDetails();

await this.TriggerAfterHooks(allHooksReversed, hookContext, evaluation, options);
await this.TriggerAfterHooks(allHooksReversed, hookContext, evaluation, options).ConfigureAwait(false);
}
catch (FeatureProviderException ex)
{
this._logger.LogError(ex, "Error while evaluating flag {FlagKey}. Error {ErrorType}", flagKey,
ex.ErrorType.GetDescription());
evaluation = new FlagEvaluationDetails<T>(flagKey, defaultValue, ex.ErrorType, Reason.Error,
string.Empty, ex.Message);
await this.TriggerErrorHooks(allHooksReversed, hookContext, ex, options);
await this.TriggerErrorHooks(allHooksReversed, hookContext, ex, options).ConfigureAwait(false);
}
catch (Exception ex)
{
this._logger.LogError(ex, "Error while evaluating flag {FlagKey}", flagKey);
var errorCode = ex is InvalidCastException ? ErrorType.TypeMismatch : ErrorType.General;
evaluation = new FlagEvaluationDetails<T>(flagKey, defaultValue, errorCode, Reason.Error, string.Empty);
await this.TriggerErrorHooks(allHooksReversed, hookContext, ex, options);
await this.TriggerErrorHooks(allHooksReversed, hookContext, ex, options).ConfigureAwait(false);
}
finally
{
await this.TriggerFinallyHooks(allHooksReversed, hookContext, options);
await this.TriggerFinallyHooks(allHooksReversed, hookContext, options).ConfigureAwait(false);
}

return evaluation;
Expand All @@ -250,7 +250,7 @@ private async Task<HookContext<T>> TriggerBeforeHooks<T>(IReadOnlyList<Hook> hoo

foreach (var hook in hooks)
{
var resp = await hook.Before(context, options?.HookHints);
var resp = await hook.Before(context, options?.HookHints).ConfigureAwait(false);
if (resp != null)
{
evalContextBuilder.Merge(resp);
Expand All @@ -271,7 +271,7 @@ private async Task TriggerAfterHooks<T>(IReadOnlyList<Hook> hooks, HookContext<T
{
foreach (var hook in hooks)
{
await hook.After(context, evaluationDetails, options?.HookHints);
await hook.After(context, evaluationDetails, options?.HookHints).ConfigureAwait(false);
}
}

Expand All @@ -282,7 +282,7 @@ private async Task TriggerErrorHooks<T>(IReadOnlyList<Hook> hooks, HookContext<T
{
try
{
await hook.Error(context, exception, options?.HookHints);
await hook.Error(context, exception, options?.HookHints).ConfigureAwait(false);
}
catch (Exception e)
{
Expand All @@ -298,7 +298,7 @@ private async Task TriggerFinallyHooks<T>(IReadOnlyList<Hook> hooks, HookContext
{
try
{
await hook.Finally(context, options?.HookHints);
await hook.Finally(context, options?.HookHints).ConfigureAwait(false);
}
catch (Exception e)
{
Expand Down