Skip to content

Commit

Permalink
Add more execute methods for ResilienceStrategy
Browse files Browse the repository at this point in the history
  • Loading branch information
martintmk committed May 2, 2023
1 parent 2d47e4f commit 5b55740
Show file tree
Hide file tree
Showing 13 changed files with 576 additions and 10 deletions.
13 changes: 13 additions & 0 deletions src/Polly.Core.Tests/ResilienceStrategyTests.Async.Task.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,26 @@ private static IEnumerable<ExecuteParameters> ExecuteAsTaskAsync_EnsureCorrectBe
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters(r => r.ExecuteAsync(async (state, t) => { state.Should().Be("state"); t.Should().Be(CancellationToken); }, "state", CancellationToken))
{
Caption = "ExecuteAsTaskAsync_StateAndCancellation",
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters(r => r.ExecuteAsync(async (_, s) => { s.Should().Be("dummy-state"); }, ResilienceContext.Get(), "dummy-state"))
{
Caption = "ExecuteAsTaskAsync_ResilienceContextAndState",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

yield return new ExecuteParameters(r => r.ExecuteAsync(async context => { }, ResilienceContext.Get()))
{
Caption = "ExecuteAsTaskAsync_ResilienceContextAndState",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

static void AssertResilienceContext(ResilienceContext context)
{
context.IsSynchronous.Should().BeFalse();
Expand Down
18 changes: 18 additions & 0 deletions src/Polly.Core.Tests/ResilienceStrategyTests.Async.TaskT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,31 @@ private static IEnumerable<ExecuteParameters> ExecuteAsTaskAsyncT_EnsureCorrectB
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters<long>(r => r.ExecuteAsync(async (state, t) =>
{
state.Should().Be("state");
t.Should().Be(CancellationToken);
return result;
}, "state", CancellationToken), result)
{
Caption = "ExecuteAsTaskAsyncT_CancellationAndState",
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters<long>(r => r.ExecuteAsync(async (_, s) => { s.Should().Be("dummy-state"); return result; }, ResilienceContext.Get(), "dummy-state"), result)
{
Caption = "ExecuteAsTaskAsyncT_ResilienceContextAndState",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

yield return new ExecuteParameters<long>(r => r.ExecuteAsync(async context => result, ResilienceContext.Get()), result)
{
Caption = "ExecuteAsTaskAsyncT_ResilienceContext",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

static void AssertResilienceContext(ResilienceContext context)
{
context.IsSynchronous.Should().BeFalse();
Expand Down
19 changes: 19 additions & 0 deletions src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,32 @@ private static IEnumerable<ExecuteParameters> ExecuteAsync_EnsureCorrectBehavior
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async (state, t) => { state.Should().Be("state"); t.Should().Be(CancellationToken); }, "state", CancellationToken))
{
Caption = "ExecuteAsync_StateAndCancellation",
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async (state, t) => { state.Should().Be("state"); t.Should().Be(CancellationToken); }, "state", CancellationToken))
{
Caption = "ExecuteAsync_StateAndCancellation",
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(async (_, s) => { s.Should().Be("dummy-state"); }, ResilienceContext.Get(), "dummy-state"))
{
Caption = "ExecuteAsync_ResilienceContextAndState",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

yield return new ExecuteParameters(r => r.ExecuteValueTaskAsync(context => default, ResilienceContext.Get()))
{
Caption = "ExecuteAsync_ResilienceContext",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

static void AssertResilienceContext(ResilienceContext context)
{
context.IsSynchronous.Should().BeFalse();
Expand Down
18 changes: 18 additions & 0 deletions src/Polly.Core.Tests/ResilienceStrategyTests.Async.ValueTaskT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,31 @@ private static IEnumerable<ExecuteParameters> ExecuteAsyncT_EnsureCorrectBehavio
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters<long>(r => r.ExecuteValueTaskAsync(async (state, t) =>
{
state.Should().Be("state");
t.Should().Be(CancellationToken);
return result;
}, "state", CancellationToken), result)
{
Caption = "ExecuteAsyncT_StateAndCancellation",
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters<long>(r => r.ExecuteValueTaskAsync(async (_, s) => { s.Should().Be("dummy-state"); return result; }, ResilienceContext.Get(), "dummy-state"), result)
{
Caption = "ExecuteAsyncT_ResilienceContextAndState",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

yield return new ExecuteParameters<long>(r => r.ExecuteValueTaskAsync(async _ => result, ResilienceContext.Get()), result)
{
Caption = "ExecuteAsyncT_ResilienceContext",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

static void AssertResilienceContext(ResilienceContext context)
{
context.IsSynchronous.Should().BeFalse();
Expand Down
25 changes: 25 additions & 0 deletions src/Polly.Core.Tests/ResilienceStrategyTests.Sync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,31 @@ private static IEnumerable<ExecuteParameters> Execute_EnsureCorrectBehavior_Exec
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters(r => r.Execute((state, t) => { state.Should().Be("state"); t.Should().Be(CancellationToken); }, "state", CancellationToken))
{
Caption = "Execute_StateAndCancellation",
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters(r => r.Execute(() => { }))
{
Caption = "Execute",
AssertContext = AssertResilienceContext,
};

yield return new ExecuteParameters(r => r.Execute(state => { state.Should().Be("state"); }, "state"))
{
Caption = "ExecuteAndState",
AssertContext = AssertResilienceContext,
};

yield return new ExecuteParameters(r => r.Execute(context => { }, ResilienceContext.Get()))
{
Caption = "ResilienceContext",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

yield return new ExecuteParameters(r => r.Execute((_, s) => { s.Should().Be("dummy-state"); }, ResilienceContext.Get(), "dummy-state"))
{
Caption = "Execute_ResilienceContextAndState",
Expand Down
28 changes: 26 additions & 2 deletions src/Polly.Core.Tests/ResilienceStrategyTests.SyncT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,35 @@ private static IEnumerable<ExecuteParameters> ExecuteT_EnsureCorrectBehavior_Exe
AssertContext = AssertResilienceContextAndToken,
};

yield return new ExecuteParameters<long>(r => r.Execute(() => result), result)
{
Caption = "ExecuteT",
AssertContext = AssertResilienceContext,
};

yield return new ExecuteParameters<long>(r => r.Execute((state) => { state.Should().Be("state"); return result; }, "state"), result)
{
Caption = "ExecuteT_State",
AssertContext = AssertResilienceContext,
};

yield return new ExecuteParameters<long>(r => r.Execute(_ => result, ResilienceContext.Get()), result)
{
Caption = "ExecuteT_ResilienceContext",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized
};

yield return new ExecuteParameters<long>(r => r.Execute((_, s) => { s.Should().Be("dummy-state"); return result; }, ResilienceContext.Get(), "dummy-state"), result)
{
Caption = "ExecuteT_ResilienceContextAndState",
Caption = "ExecuteT_ResilienceContext",
AssertContext = AssertResilienceContext,
AssertContextAfter = AssertContextInitialized,
};

yield return new ExecuteParameters<long>(r => r.Execute((state, _) => { state.Should().Be("dummy-state"); return result; }, "dummy-state", CancellationToken), result)
{
Caption = "ExecuteT_StateAndCancellation",
AssertContext = AssertResilienceContextAndToken,
};

static void AssertResilienceContext(ResilienceContext context)
Expand Down
16 changes: 8 additions & 8 deletions src/Polly.Core.Tests/Retry/RetryResilienceStrategyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void ShouldRetryEmpty_Skipped()
SetupNoDelay();
var sut = CreateSut();

sut.Execute(_ => 0, default);
sut.Execute(() => 0);

called.Should().BeFalse();
}
Expand All @@ -36,7 +36,7 @@ public void Retry_RetryCount_Respected()
SetupNoDelay();
var sut = CreateSut();

sut.Execute(_ => 0, default);
sut.Execute(() => 0);

calls.Should().Be(12);
}
Expand All @@ -55,7 +55,7 @@ public void RetryException_RetryCount_Respected()
SetupNoDelay();
var sut = CreateSut();

Assert.Throws<InvalidOperationException>(() => sut.Execute<int>(_ => throw new InvalidOperationException(), default));
Assert.Throws<InvalidOperationException>(() => sut.Execute<int>(() => throw new InvalidOperationException()));

calls.Should().Be(3);
}
Expand All @@ -79,7 +79,7 @@ public void Retry_Infinite_Respected()
SetupNoDelay();
var sut = CreateSut();

Assert.Throws<InvalidOperationException>(() => sut.Execute(_ => 0, default));
Assert.Throws<InvalidOperationException>(() => sut.Execute(() => 0));

calls.Should().Be(RetryConstants.MaxRetryCount + 1);
}
Expand All @@ -97,7 +97,7 @@ public void RetryDelayGenerator_Respected()

var sut = CreateSut();

sut.Execute(_ => 0, default);
sut.Execute(() => 0);

_timeProvider.Verify(v => v.Delay(TimeSpan.FromMilliseconds(123), default), Times.Exactly(3));
}
Expand All @@ -123,7 +123,7 @@ public void OnRetry_EnsureCorrectArguments()

var sut = CreateSut();

sut.Execute(_ => 0, default);
sut.Execute(() => 0);

attempts.Should().HaveCount(3);
attempts[0].Should().Be(0);
Expand All @@ -150,7 +150,7 @@ public void OnRetry_EnsureTelemetry()

var sut = CreateSut();

sut.Execute(_ => 0, default);
sut.Execute(() => 0);

_diagnosticSource.VerifyAll();
}
Expand Down Expand Up @@ -178,7 +178,7 @@ public void RetryDelayGenerator_EnsureCorrectArguments()

var sut = CreateSut();

sut.Execute(_ => 0, default);
sut.Execute(() => 0);

attempts.Should().HaveCount(3);
attempts[0].Should().Be(0);
Expand Down
59 changes: 59 additions & 0 deletions src/Polly.Core/ResilienceStrategy.Async.Task.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,65 @@ static async (context, state) =>
(callback, state)).ConfigureAwait(context.ContinueOnCapturedContext);
}

/// <summary>
/// Executes the specified callback.
/// </summary>
/// <param name="callback">The user-provided callback.</param>
/// <param name="context">The context associated with the callback.</param>
/// <returns>The instance of <see cref="Task"/> that represents the asynchronous execution.</returns>
public async Task ExecuteAsync(
Func<ResilienceContext, Task> callback,
ResilienceContext context)
{
Guard.NotNull(callback);
Guard.NotNull(context);

InitializeAsyncContext(context);

await ExecuteCoreAsync(
static async (context, state) =>
{
await state(context).ConfigureAwait(context.ContinueOnCapturedContext);
return VoidResult.Instance;
},
context,
callback).ConfigureAwait(context.ContinueOnCapturedContext);
}

/// <summary>
/// Executes the specified callback.
/// </summary>
/// <typeparam name="TState">The type of state associated with the callback.</typeparam>
/// <param name="callback">The user-provided callback.</param>
/// <param name="state">The state associated with the callback.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> associated with the callback.</param>
/// <returns>The instance of <see cref="Task"/> that represents the asynchronous execution.</returns>
public async Task ExecuteAsync<TState>(
Func<TState, CancellationToken, Task> callback,
TState state,
CancellationToken cancellationToken)
{
Guard.NotNull(callback);

var context = GetAsyncContext(cancellationToken);

try
{
await ExecuteCoreAsync(
static async (context, state) =>
{
await state.callback(state.state, context.CancellationToken).ConfigureAwait(context.ContinueOnCapturedContext);
return VoidResult.Instance;
},
context,
(callback, state)).ConfigureAwait(context.ContinueOnCapturedContext);
}
finally
{
ResilienceContext.Return(context);
}
}

/// <summary>
/// Executes the specified callback.
/// </summary>
Expand Down
Loading

0 comments on commit 5b55740

Please sign in to comment.