Skip to content

Commit

Permalink
refactor: Use ValueTask on plumbing methods
Browse files Browse the repository at this point in the history
Switch to ValueTask on methods that are likely to complete
synchronously and/or be populated with contrib-/user-provided
delegates.

Signed-off-by: Austin Drenski <austin@austindrenski.io>
  • Loading branch information
austindrenski committed Jan 17, 2024
1 parent 0dc319f commit adaf67d
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 69 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,25 +295,25 @@ To satisfy the interface, all methods (`BeforeAsync`/`AfterAsync`/`FinallyAsync`
```csharp
public class MyHook : Hook
{
public Task<EvaluationContext> BeforeAsync<T>(HookContext<T> context,
public ValueTask<EvaluationContext> BeforeAsync<T>(HookContext<T> context,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
// code to run before flag evaluation
}

public virtual Task AfterAsync<T>(HookContext<T> context, FlagEvaluationDetails<T> details,
public virtual ValueTask AfterAsync<T>(HookContext<T> context, FlagEvaluationDetails<T> details,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
// code to run after successful flag evaluation
}

public virtual Task ErrorAsync<T>(HookContext<T> context, Exception error,
public virtual ValueTask ErrorAsync<T>(HookContext<T> context, Exception error,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
// code to run if there's an error during before hooks or during flag evaluation
}

public virtual Task FinallyAsync<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
public virtual ValueTask FinallyAsync<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
// code to run after all other stages, regardless of success/failure
}
Expand Down
6 changes: 3 additions & 3 deletions src/OpenFeature/Api.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private Api() { }
/// <remarks>The provider cannot be set to null. Attempting to set the provider to null has no effect.</remarks>
/// <param name="featureProvider">Implementation of <see cref="FeatureProvider"/></param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
public async Task SetProviderAsync(FeatureProvider featureProvider, CancellationToken cancellationToken = default)
public async ValueTask SetProviderAsync(FeatureProvider featureProvider, CancellationToken cancellationToken = default)
{
this.EventExecutor.RegisterDefaultFeatureProvider(featureProvider);
await this._repository.SetProviderAsync(featureProvider, this.GetContext(), cancellationToken: cancellationToken).ConfigureAwait(false);
Expand All @@ -58,7 +58,7 @@ public async Task SetProviderAsync(FeatureProvider featureProvider, Cancellation
/// <param name="clientName">Name of client</param>
/// <param name="featureProvider">Implementation of <see cref="FeatureProvider"/></param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
public async Task SetProviderAsync(string clientName, FeatureProvider featureProvider, CancellationToken cancellationToken = default)
public async ValueTask SetProviderAsync(string clientName, FeatureProvider featureProvider, CancellationToken cancellationToken = default)
{
this.EventExecutor.RegisterClientFeatureProvider(clientName, featureProvider);
await this._repository.SetProviderAsync(clientName, featureProvider, this.GetContext(), cancellationToken: cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -206,7 +206,7 @@ public EvaluationContext GetContext()
/// </para>
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
public async Task ShutdownAsync(CancellationToken cancellationToken = default)
public async ValueTask ShutdownAsync(CancellationToken cancellationToken = default)
{
await this._repository.ShutdownAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
await this.EventExecutor.ShutdownAsync(cancellationToken).ConfigureAwait(false);
Expand Down
6 changes: 3 additions & 3 deletions src/OpenFeature/EventExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
namespace OpenFeature
{

internal delegate Task ShutdownDelegate(CancellationToken cancellationToken);
internal delegate ValueTask ShutdownDelegate(CancellationToken cancellationToken);

internal class EventExecutor
{
Expand Down Expand Up @@ -327,7 +327,7 @@ private void InvokeEventHandler(EventHandlerDelegate eventHandler, Event e)
}
}

public async Task ShutdownAsync(CancellationToken cancellationToken = default)
public async ValueTask ShutdownAsync(CancellationToken cancellationToken = default)
{
await this._shutdownDelegate(cancellationToken).ConfigureAwait(false);
}
Expand All @@ -338,7 +338,7 @@ internal void SetShutdownDelegate(ShutdownDelegate del)
}

// Method to signal shutdown
private async Task SignalShutdownAsync(CancellationToken cancellationToken)
private async ValueTask SignalShutdownAsync(CancellationToken cancellationToken)
{
// Enqueue a shutdown signal
await this.EventChannel.Writer.WriteAsync(new ShutdownSignal(), cancellationToken).ConfigureAwait(false);
Expand Down
8 changes: 4 additions & 4 deletions src/OpenFeature/FeatureProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ public abstract Task<ResolutionDetails<Value>> ResolveStructureValueAsync(string
/// the <see cref="GetStatus"/> method after initialization is complete.
/// </para>
/// </remarks>
public virtual Task InitializeAsync(EvaluationContext context, CancellationToken cancellationToken = default)
public virtual ValueTask InitializeAsync(EvaluationContext context, CancellationToken cancellationToken = default)
{
// Intentionally left blank.
return Task.CompletedTask;
return new ValueTask();
}

/// <summary>
Expand All @@ -137,10 +137,10 @@ public virtual Task InitializeAsync(EvaluationContext context, CancellationToken
/// </summary>
/// <returns>A task that completes when the shutdown process is complete.</returns>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
public virtual Task ShutdownAsync(CancellationToken cancellationToken = default)
public virtual ValueTask ShutdownAsync(CancellationToken cancellationToken = default)
{
// Intentionally left blank.
return Task.CompletedTask;
return new ValueTask();
}

/// <summary>
Expand Down
16 changes: 8 additions & 8 deletions src/OpenFeature/Hook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ public abstract class Hook
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <typeparam name="T">Flag value type (bool|number|string|object)</typeparam>
/// <returns>Modified EvaluationContext that is used for the flag evaluation</returns>
public virtual Task<EvaluationContext> BeforeAsync<T>(HookContext<T> context,
public virtual ValueTask<EvaluationContext> BeforeAsync<T>(HookContext<T> context,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
return Task.FromResult(EvaluationContext.Empty);
return new ValueTask<EvaluationContext>(EvaluationContext.Empty);
}

/// <summary>
Expand All @@ -44,10 +44,10 @@ public virtual Task<EvaluationContext> BeforeAsync<T>(HookContext<T> context,
/// <param name="hints">Caller provided data</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <typeparam name="T">Flag value type (bool|number|string|object)</typeparam>
public virtual Task AfterAsync<T>(HookContext<T> context, FlagEvaluationDetails<T> details,
public virtual ValueTask AfterAsync<T>(HookContext<T> context, FlagEvaluationDetails<T> details,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
return new ValueTask();
}

/// <summary>
Expand All @@ -58,10 +58,10 @@ public virtual Task AfterAsync<T>(HookContext<T> context, FlagEvaluationDetails<
/// <param name="hints">Caller provided data</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <typeparam name="T">Flag value type (bool|number|string|object)</typeparam>
public virtual Task ErrorAsync<T>(HookContext<T> context, Exception error,
public virtual ValueTask ErrorAsync<T>(HookContext<T> context, Exception error,
IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
return new ValueTask();
}

/// <summary>
Expand All @@ -71,9 +71,9 @@ public virtual Task ErrorAsync<T>(HookContext<T> context, Exception error,
/// <param name="hints">Caller provided data</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
/// <typeparam name="T">Flag value type (bool|number|string|object)</typeparam>
public virtual Task FinallyAsync<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
public virtual ValueTask FinallyAsync<T>(HookContext<T> context, IReadOnlyDictionary<string, object> hints = null, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
return new ValueTask();
}
}
}
8 changes: 4 additions & 4 deletions src/OpenFeature/OpenFeatureClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ private async Task<FlagEvaluationDetails<T>> EvaluateFlagAsync<T>(
return evaluation;
}

private async Task<HookContext<T>> TriggerBeforeHooksAsync<T>(IReadOnlyList<Hook> hooks, HookContext<T> context,
private async ValueTask<HookContext<T>> TriggerBeforeHooksAsync<T>(IReadOnlyList<Hook> hooks, HookContext<T> context,
FlagEvaluationOptions options, CancellationToken cancellationToken = default)
{
var evalContextBuilder = EvaluationContext.Builder();
Expand All @@ -280,7 +280,7 @@ private async Task<HookContext<T>> TriggerBeforeHooksAsync<T>(IReadOnlyList<Hook
return context.WithNewEvaluationContext(evalContextBuilder.Build());
}

private async Task TriggerAfterHooksAsync<T>(IReadOnlyList<Hook> hooks, HookContext<T> context,
private async ValueTask TriggerAfterHooksAsync<T>(IReadOnlyList<Hook> hooks, HookContext<T> context,
FlagEvaluationDetails<T> evaluationDetails, FlagEvaluationOptions options, CancellationToken cancellationToken = default)
{
foreach (var hook in hooks)
Expand All @@ -289,7 +289,7 @@ private async Task TriggerAfterHooksAsync<T>(IReadOnlyList<Hook> hooks, HookCont
}
}

private async Task TriggerErrorHooksAsync<T>(IReadOnlyList<Hook> hooks, HookContext<T> context, Exception exception,
private async ValueTask TriggerErrorHooksAsync<T>(IReadOnlyList<Hook> hooks, HookContext<T> context, Exception exception,
FlagEvaluationOptions options, CancellationToken cancellationToken = default)
{
foreach (var hook in hooks)
Expand All @@ -305,7 +305,7 @@ private async Task TriggerErrorHooksAsync<T>(IReadOnlyList<Hook> hooks, HookCont
}
}

private async Task TriggerFinallyHooksAsync<T>(IReadOnlyList<Hook> hooks, HookContext<T> context,
private async ValueTask TriggerFinallyHooksAsync<T>(IReadOnlyList<Hook> hooks, HookContext<T> context,
FlagEvaluationOptions options, CancellationToken cancellationToken = default)
{
foreach (var hook in hooks)
Expand Down
12 changes: 6 additions & 6 deletions src/OpenFeature/ProviderRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal class ProviderRepository
/// </param>
/// <param name="afterShutdown">called after a provider is shutdown, can be used to remove event handlers</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
public async Task SetProviderAsync(
public async ValueTask SetProviderAsync(
FeatureProvider featureProvider,
EvaluationContext context,
Action<FeatureProvider> afterSet = null,
Expand Down Expand Up @@ -98,7 +98,7 @@ await InitProviderAsync(this._defaultProvider, context, afterInitialization, aft
.ConfigureAwait(false);
}

private static async Task InitProviderAsync(
private static async ValueTask InitProviderAsync(
FeatureProvider newProvider,
EvaluationContext context,
Action<FeatureProvider> afterInitialization,
Expand Down Expand Up @@ -148,7 +148,7 @@ private static async Task InitProviderAsync(
/// </param>
/// <param name="afterShutdown">called after a provider is shutdown, can be used to remove event handlers</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
public async Task SetProviderAsync(string clientName,
public async ValueTask SetProviderAsync(string clientName,
FeatureProvider featureProvider,
EvaluationContext context,
Action<FeatureProvider> afterSet = null,
Expand Down Expand Up @@ -198,7 +198,7 @@ public async Task SetProviderAsync(string clientName,
/// <remarks>
/// Shutdown the feature provider if it is unused. This must be called within a write lock of the _providersLock.
/// </remarks>
private async Task ShutdownIfUnusedAsync(
private async ValueTask ShutdownIfUnusedAsync(
FeatureProvider targetProvider,
Action<FeatureProvider> afterShutdown,
Action<FeatureProvider, Exception> afterError,
Expand Down Expand Up @@ -226,7 +226,7 @@ private async Task ShutdownIfUnusedAsync(
/// it would not be meaningful to emit an error.
/// </para>
/// </remarks>
private static async Task SafeShutdownProviderAsync(FeatureProvider targetProvider,
private static async ValueTask SafeShutdownProviderAsync(FeatureProvider targetProvider,
Action<FeatureProvider> afterShutdown,
Action<FeatureProvider, Exception> afterError,
CancellationToken cancellationToken)
Expand Down Expand Up @@ -267,7 +267,7 @@ public FeatureProvider GetProvider(string clientName)
: this.GetProvider();
}

public async Task ShutdownAsync(Action<FeatureProvider, Exception> afterError = null, CancellationToken cancellationToken = default)
public async ValueTask ShutdownAsync(Action<FeatureProvider, Exception> afterError = null, CancellationToken cancellationToken = default)
{
var providers = new HashSet<FeatureProvider>();
this._providersLock.EnterWriteLock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public EvaluationStepDefinitions(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
var flagdProvider = new FlagdProvider();
Api.Instance.SetProviderAsync(flagdProvider).Wait();
Api.Instance.SetProviderAsync(flagdProvider).GetAwaiter().GetResult();
client = Api.Instance.GetClient();
}

Expand Down
2 changes: 1 addition & 1 deletion test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public ClearOpenFeatureInstanceFixture()
{
Api.Instance.SetContext(null);
Api.Instance.ClearHooks();
Api.Instance.SetProviderAsync(new NoOpFeatureProvider()).Wait();
Api.Instance.SetProviderAsync(new NoOpFeatureProvider()).GetAwaiter().GetResult();
}
}
}
Loading

0 comments on commit adaf67d

Please sign in to comment.