Skip to content

Commit

Permalink
added optional predicate to OnError that indicates that error handlin…
Browse files Browse the repository at this point in the history
…g should apply or not
  • Loading branch information
mvSapphire committed Aug 31, 2023
1 parent 3f5f055 commit 843e0d6
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 14 deletions.
7 changes: 5 additions & 2 deletions src/PowerPipe/Builder/PipelineBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ public PipelineBuilder<TContext, TResult> If(Func<bool> predicate, Func<Pipeline
return this;
}

public PipelineBuilder<TContext, TResult> OnError(PipelineStepErrorHandling errorHandling, TimeSpan? retryInterval = null, int? maxRetryCount = null)
public PipelineBuilder<TContext, TResult> OnError(PipelineStepErrorHandling errorHandling,
TimeSpan? retryInterval = null,
int? maxRetryCount = null,
Predicate<TContext> predicate = null)
{
if (errorHandling is PipelineStepErrorHandling.Retry)
{
Expand All @@ -74,7 +77,7 @@ public PipelineBuilder<TContext, TResult> OnError(PipelineStepErrorHandling erro

var lastStep = _steps[^1];

lastStep.ConfigureErrorHandling(errorHandling, retryInterval, maxRetryCount);
lastStep.ConfigureErrorHandling(errorHandling, retryInterval, maxRetryCount, predicate);

return this;
}
Expand Down
8 changes: 7 additions & 1 deletion src/PowerPipe/Builder/Steps/InternalStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ internal abstract class InternalStep<TContext> : IPipelineStep<TContext>

protected virtual int? MaxRetryCount { get; private set; }

protected virtual Predicate<TContext> ErrorHandlingPredicate { get; private set; }

private int RetryCount { get; set; }

public void ConfigureErrorHandling(PipelineStepErrorHandling errorHandling, TimeSpan? retryInterval, int? maxRetryCount)
public void ConfigureErrorHandling(PipelineStepErrorHandling errorHandling, TimeSpan? retryInterval, int? maxRetryCount, Predicate<TContext> predicate)
{
ErrorHandlingBehaviour = errorHandling;
RetryInterval = retryInterval;
MaxRetryCount = maxRetryCount;
ErrorHandlingPredicate = predicate;
}

public async Task ExecuteAsync(TContext context, CancellationToken cancellationToken)
Expand All @@ -44,6 +47,9 @@ protected virtual Task ExecuteInternalAsync(TContext context, CancellationToken

protected virtual async Task<bool> HandleExceptionAsync(TContext context, CancellationToken cancellationToken)
{
if (ErrorHandlingPredicate is not null && !ErrorHandlingPredicate(context))
return false;

switch (ErrorHandlingBehaviour)
{
case PipelineStepErrorHandling.Suppress:
Expand Down
33 changes: 22 additions & 11 deletions tests/PowerPipe.UnitTests/PipelineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,11 @@ public async Task IfStep_Succeed(bool predicate)
}

[Theory]
[InlineData(PipelineStepErrorHandling.Suppress)]
[InlineData(PipelineStepErrorHandling.Retry)]
public async Task OnError_Succeed(PipelineStepErrorHandling errorHandlingBehaviour)
[InlineData(PipelineStepErrorHandling.Suppress, true)]
[InlineData(PipelineStepErrorHandling.Retry, true)]
[InlineData(PipelineStepErrorHandling.Suppress, false)]
[InlineData(PipelineStepErrorHandling.Retry, false)]
public async Task OnError_Succeed(PipelineStepErrorHandling errorHandlingBehaviour, bool applyErrorHandling)
{
var step = Substitute.For<TestStep1>();

Expand All @@ -147,24 +149,33 @@ public async Task OnError_Succeed(PipelineStepErrorHandling errorHandlingBehavio
var retryCount = 3;
var isRetryBehaviour = errorHandlingBehaviour is PipelineStepErrorHandling.Retry;

bool ShouldApplyErrorHandling(TestPipelineContext context) => applyErrorHandling;

var pipeline = new PipelineBuilder<TestPipelineContext, TestPipelineResult>(stepFactory, context)
.Add<TestStep1>()
.OnError(errorHandlingBehaviour, maxRetryCount: isRetryBehaviour ? retryCount : default)
.OnError(errorHandlingBehaviour, maxRetryCount: isRetryBehaviour ? retryCount : default, predicate: ShouldApplyErrorHandling)
.Build();

var action = () => pipeline.RunAsync(cts.Token);

if (isRetryBehaviour)
if (applyErrorHandling)
{
await action.Should().ThrowAsync<InvalidOperationException>().WithMessage(exceptionMessage);

await step.Received(1 + retryCount).ExecuteAsync(Arg.Is(context), Arg.Is(cts.Token));
if (isRetryBehaviour)
{
await action.Should().ThrowAsync<InvalidOperationException>().WithMessage(exceptionMessage);

await step.Received(1 + retryCount).ExecuteAsync(Arg.Is(context), Arg.Is(cts.Token));
}
else
{
await action.Should().NotThrowAsync<InvalidOperationException>();

await step.Received(1).ExecuteAsync(Arg.Is(context), Arg.Is(cts.Token));
}
}
else
{
await action.Should().NotThrowAsync<InvalidOperationException>();

await step.Received(1).ExecuteAsync(Arg.Is(context), Arg.Is(cts.Token));
await action.Should().ThrowAsync<InvalidOperationException>().WithMessage(exceptionMessage);
}
}
}

0 comments on commit 843e0d6

Please sign in to comment.