diff --git a/samples/PowerPipe.Sample/PowerPipe.Sample.csproj b/samples/PowerPipe.Sample/PowerPipe.Sample.csproj
index 6ed4bad..1d37e1a 100644
--- a/samples/PowerPipe.Sample/PowerPipe.Sample.csproj
+++ b/samples/PowerPipe.Sample/PowerPipe.Sample.csproj
@@ -15,6 +15,8 @@
+
+
diff --git a/samples/PowerPipe.Sample/Program.cs b/samples/PowerPipe.Sample/Program.cs
index 94c4557..d521d7e 100644
--- a/samples/PowerPipe.Sample/Program.cs
+++ b/samples/PowerPipe.Sample/Program.cs
@@ -2,6 +2,7 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
using PowerPipe.Sample.Steps;
namespace PowerPipe.Sample;
@@ -30,6 +31,13 @@ private static IServiceProvider ConfigureServices()
.AddScoped(typeof(SampleGenericStep<>));
});
+ services.AddLogging(options =>
+ {
+ options
+ .AddConsole()
+ .SetMinimumLevel(LogLevel.Debug);
+ });
+
services.AddSingleton();
var serviceProvider = services.BuildServiceProvider();
diff --git a/samples/PowerPipe.Sample/Steps/SampleGenericStep.cs b/samples/PowerPipe.Sample/Steps/SampleGenericStep.cs
index f786e69..1dad5b1 100644
--- a/samples/PowerPipe.Sample/Steps/SampleGenericStep.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleGenericStep.cs
@@ -11,7 +11,6 @@ public class SampleGenericStep: IPipelineStep
public async ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleGenericStep)} Executed");
await NextStep.ExecuteAsync(context, cancellationToken);
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleParallelStep1.cs b/samples/PowerPipe.Sample/Steps/SampleParallelStep1.cs
index f768f74..3a5467f 100644
--- a/samples/PowerPipe.Sample/Steps/SampleParallelStep1.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleParallelStep1.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,7 +8,6 @@ public class SampleParallelStep1 : IPipelineParallelStep
{
public ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleParallelStep1)} Executed");
return ValueTask.CompletedTask;
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleParallelStep2.cs b/samples/PowerPipe.Sample/Steps/SampleParallelStep2.cs
index 355ad3f..15833e3 100644
--- a/samples/PowerPipe.Sample/Steps/SampleParallelStep2.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleParallelStep2.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,7 +8,6 @@ public class SampleParallelStep2 : IPipelineParallelStep
{
public ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleParallelStep2)} Executed");
return ValueTask.CompletedTask;
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleParallelStep3.cs b/samples/PowerPipe.Sample/Steps/SampleParallelStep3.cs
index dad6573..a7f9edc 100644
--- a/samples/PowerPipe.Sample/Steps/SampleParallelStep3.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleParallelStep3.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,7 +8,6 @@ public class SampleParallelStep3 : IPipelineParallelStep
{
public ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleParallelStep3)} Executed");
return ValueTask.CompletedTask;
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleParallelStep4.cs b/samples/PowerPipe.Sample/Steps/SampleParallelStep4.cs
index c9a3ee0..e0a443f 100644
--- a/samples/PowerPipe.Sample/Steps/SampleParallelStep4.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleParallelStep4.cs
@@ -9,8 +9,6 @@ public class SampleParallelStep4 : IPipelineParallelStep
{
public ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleParallelStep4)} Executed");
-
throw new InvalidOperationException();
// return ValueTask.CompletedTask;
diff --git a/samples/PowerPipe.Sample/Steps/SampleParallelStep5.cs b/samples/PowerPipe.Sample/Steps/SampleParallelStep5.cs
index 54f7aae..edd51f6 100644
--- a/samples/PowerPipe.Sample/Steps/SampleParallelStep5.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleParallelStep5.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,8 +8,6 @@ public class SampleParallelStep5 : IPipelineParallelStep
{
public ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleParallelStep5)} Executed");
-
// throw new InvalidOperationException();
return ValueTask.CompletedTask;
diff --git a/samples/PowerPipe.Sample/Steps/SampleParallelStep5Compensation.cs b/samples/PowerPipe.Sample/Steps/SampleParallelStep5Compensation.cs
index ff8f286..c4b9141 100644
--- a/samples/PowerPipe.Sample/Steps/SampleParallelStep5Compensation.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleParallelStep5Compensation.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,7 +8,6 @@ public class SampleParallelStep5Compensation : IPipelineCompensationStep
{
public ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleParallelStep6)} Executed");
return ValueTask.CompletedTask;
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleParallelStep7.cs b/samples/PowerPipe.Sample/Steps/SampleParallelStep7.cs
index 1534b6d..25e142f 100644
--- a/samples/PowerPipe.Sample/Steps/SampleParallelStep7.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleParallelStep7.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,7 +8,6 @@ public class SampleParallelStep7 : IPipelineParallelStep
{
public ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleParallelStep7)} Executed");
return ValueTask.CompletedTask;
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleStep1.cs b/samples/PowerPipe.Sample/Steps/SampleStep1.cs
index f9ba88a..75df497 100644
--- a/samples/PowerPipe.Sample/Steps/SampleStep1.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleStep1.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -10,7 +9,6 @@ public class SampleStep1 : IPipelineStep
public IPipelineStep NextStep { get; set; }
public async ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleStep1)} Executed");
await NextStep.ExecuteAsync(context, cancellationToken);
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleStep1Compensation.cs b/samples/PowerPipe.Sample/Steps/SampleStep1Compensation.cs
index e08c484..f4ab175 100644
--- a/samples/PowerPipe.Sample/Steps/SampleStep1Compensation.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleStep1Compensation.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,7 +8,6 @@ public class SampleStep1Compensation : IPipelineCompensationStep
public IPipelineStep NextStep { get; set; }
public async ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleStep2)} Executed");
await NextStep.ExecuteAsync(context, cancellationToken);
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleStep2Compensation.cs b/samples/PowerPipe.Sample/Steps/SampleStep2Compensation.cs
index 8b5ad49..1eb08c6 100644
--- a/samples/PowerPipe.Sample/Steps/SampleStep2Compensation.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleStep2Compensation.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,7 +8,6 @@ public class SampleStep2Compensation : IPipelineCompensationStep
public IPipelineStep NextStep { get; set; }
public async ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleStep3)} Executed");
await NextStep.ExecuteAsync(context, cancellationToken);
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleStep4.cs b/samples/PowerPipe.Sample/Steps/SampleStep4.cs
index bf90f4d..e8335f6 100644
--- a/samples/PowerPipe.Sample/Steps/SampleStep4.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleStep4.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -10,7 +9,6 @@ public class SampleStep4 : IPipelineStep
public IPipelineStep NextStep { get; set; }
public async ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleStep4)} Executed");
await NextStep.ExecuteAsync(context, cancellationToken);
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleStep5.cs b/samples/PowerPipe.Sample/Steps/SampleStep5.cs
index 1cb2352..c4f4552 100644
--- a/samples/PowerPipe.Sample/Steps/SampleStep5.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleStep5.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -10,7 +9,6 @@ public class SampleStep5 : IPipelineStep
public IPipelineStep NextStep { get; set; }
public async ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleStep5)} Executed");
await NextStep.ExecuteAsync(context, cancellationToken);
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleStep6.cs b/samples/PowerPipe.Sample/Steps/SampleStep6.cs
index 68c8993..181ffe0 100644
--- a/samples/PowerPipe.Sample/Steps/SampleStep6.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleStep6.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -10,7 +9,6 @@ public class SampleStep6 : IPipelineStep
public IPipelineStep NextStep { get; set; }
public async ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleStep6)} Executed");
await NextStep.ExecuteAsync(context, cancellationToken);
}
}
diff --git a/samples/PowerPipe.Sample/Steps/SampleStep7.cs b/samples/PowerPipe.Sample/Steps/SampleStep7.cs
index 7ef260f..fc3b8cf 100644
--- a/samples/PowerPipe.Sample/Steps/SampleStep7.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleStep7.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -10,8 +9,6 @@ public class SampleStep7 : IPipelineStep
public IPipelineStep NextStep { get; set; }
public async ValueTask ExecuteAsync(SamplePipelineContext context, CancellationToken cancellationToken)
{
- Console.WriteLine($"{nameof(SampleStep7)} Executed");
-
// throw new InvalidOperationException();
await NextStep.ExecuteAsync(context, cancellationToken);
diff --git a/samples/PowerPipe.Sample/Steps/SampleStep7Compensation.cs b/samples/PowerPipe.Sample/Steps/SampleStep7Compensation.cs
index c5e8594..be9ac7d 100644
--- a/samples/PowerPipe.Sample/Steps/SampleStep7Compensation.cs
+++ b/samples/PowerPipe.Sample/Steps/SampleStep7Compensation.cs
@@ -1,4 +1,3 @@
-using System;
using System.Threading;
using System.Threading.Tasks;
using PowerPipe.Interfaces;
@@ -9,7 +8,6 @@ public class SampleStep7Compensation : IPipelineCompensationStep
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/src/PowerPipe/Builder/PipelineBuilder.cs b/src/PowerPipe/Builder/PipelineBuilder.cs
index ccb04c7..c2163e9 100644
--- a/src/PowerPipe/Builder/PipelineBuilder.cs
+++ b/src/PowerPipe/Builder/PipelineBuilder.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using Microsoft.Extensions.Logging;
using PowerPipe.Builder.Steps;
using PowerPipe.Interfaces;
@@ -15,6 +16,7 @@ public sealed class PipelineBuilder
where TResult : class
{
private readonly IPipelineStepFactory _pipelineStepFactory;
+ private readonly ILoggerFactory _loggerFactory;
private volatile TContext _context;
internal List> Steps { get; } = new();
@@ -32,6 +34,7 @@ public PipelineBuilder(IPipelineStepFactory pipelineStepFactory, TContext contex
_pipelineStepFactory = pipelineStepFactory;
_context = context;
+ _loggerFactory = pipelineStepFactory.ServiceProvider.GetService(typeof(ILoggerFactory)) as ILoggerFactory;
}
///
@@ -42,7 +45,7 @@ public PipelineBuilder(IPipelineStepFactory pipelineStepFactory, TContext contex
public PipelineBuilder Add()
where T : IStepBase
{
- Steps.Add(new LazyStep(_pipelineStepFactory.Create));
+ Steps.Add(new LazyStep(_pipelineStepFactory.Create, _loggerFactory));
return this;
}
@@ -56,7 +59,9 @@ public PipelineBuilder Add()
public PipelineBuilder AddIf(Predicate predicate)
where T : IStepBase
{
- Steps.Add(new AddIfStep(predicate, new LazyStep(_pipelineStepFactory.Create)));
+ Steps.Add(new AddIfStep(
+ predicate,
+ new LazyStep(_pipelineStepFactory.Create, _loggerFactory)));
return this;
}
@@ -74,8 +79,8 @@ public PipelineBuilder AddIfElse(Predicate(
predicate,
- new LazyStep(_pipelineStepFactory.Create),
- new LazyStep(_pipelineStepFactory.Create)));
+ new LazyStep(_pipelineStepFactory.Create, _loggerFactory),
+ new LazyStep(_pipelineStepFactory.Create, _loggerFactory)));
return this;
}
@@ -151,4 +156,4 @@ public IPipeline Build()
return new Pipeline(_context, Steps);
}
-}
\ No newline at end of file
+}
diff --git a/src/PowerPipe/Builder/Steps/InternalStep.cs b/src/PowerPipe/Builder/Steps/InternalStep.cs
index 97cba3a..2f0d1cb 100644
--- a/src/PowerPipe/Builder/Steps/InternalStep.cs
+++ b/src/PowerPipe/Builder/Steps/InternalStep.cs
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
using PowerPipe.Exceptions;
using PowerPipe.Interfaces;
@@ -20,6 +21,11 @@ internal abstract class InternalStep : IPipelineStep, IPipel
///
public CompensationStep CompensationStep { get; set; }
+ ///
+ /// Gets or init a logger.
+ ///
+ protected ILogger Logger { get; set; }
+
///
/// Gets or sets a value indicating whether this step has been executed.
///
@@ -89,6 +95,8 @@ public async ValueTask ExecuteAsync(TContext context, CancellationToken cancella
throw;
}
+ Logger?.LogDebug("Exception thrown during execution. {exception}", e);
+
ErrorHandledSucceed = await HandleExceptionAsync(context, cancellationToken);
if (!ErrorHandledSucceed.Value)
@@ -97,7 +105,10 @@ public async ValueTask ExecuteAsync(TContext context, CancellationToken cancella
finally
{
if (AllowedToCompensate)
+ {
+ Logger?.LogDebug("Exception handling failed, compensation executed");
await CompensationStep.CompensateAsync(context, cancellationToken);
+ }
}
}
@@ -118,25 +129,38 @@ protected virtual ValueTask ExecuteInternalAsync(TContext context, CancellationT
/// A task representing the asynchronous operation. Returns true if the exception is handled; otherwise, false.
protected virtual async ValueTask HandleExceptionAsync(TContext context, CancellationToken cancellationToken)
{
+ Logger?.LogDebug("Exception handling executed");
+
if (ErrorHandlingPredicate is not null && !ErrorHandlingPredicate(context))
+ {
+ Logger?.LogDebug("Exception not handled due to error handling predicate");
return false;
+ }
switch (ErrorHandlingBehaviour)
{
case PipelineStepErrorHandling.Suppress:
+ Logger?.LogDebug("Exception suppressed");
return true;
case PipelineStepErrorHandling.Retry:
break;
case null:
+ Logger?.LogDebug("Exception not handled due to absence of handling behaviour");
return false;
}
if (RetryCount >= (MaxRetryCount ?? 1))
+ {
+ Logger?.LogDebug("Exception retry count exceeded");
return false;
+ }
RetryCount++;
+
+ Logger?.LogDebug("Step execution retry after delay, {count}", RetryCount);
+
await Task.Delay(RetryInterval ?? TimeSpan.FromSeconds(1), cancellationToken);
await ExecuteAsync(context, cancellationToken);
diff --git a/src/PowerPipe/Builder/Steps/LazyStep.cs b/src/PowerPipe/Builder/Steps/LazyStep.cs
index 787daed..ffae4dc 100644
--- a/src/PowerPipe/Builder/Steps/LazyStep.cs
+++ b/src/PowerPipe/Builder/Steps/LazyStep.cs
@@ -1,6 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
using PowerPipe.Interfaces;
namespace PowerPipe.Builder.Steps;
@@ -17,7 +18,8 @@ internal class LazyStep : InternalStep
/// Initializes a new instance of the class.
///
/// A factory function to create the step when needed.
- internal LazyStep(Func> factory)
+ /// A logger factory
+ internal LazyStep(Func> factory, ILoggerFactory loggerFactory)
{
_step = new Lazy>(() =>
{
@@ -26,6 +28,8 @@ internal LazyStep(Func> factory)
if (instance is IPipelineStep step)
step.NextStep = NextStep;
+ Logger = loggerFactory?.CreateLogger(instance.GetType());
+
return instance;
});
}
@@ -41,5 +45,7 @@ protected override async ValueTask ExecuteInternalAsync(TContext context, Cancel
StepExecuted = true;
await _step.Value.ExecuteAsync(context, cancellationToken);
+
+ Logger?.LogDebug("{Step} executed", _step.Value.GetType().FullName);
}
}
diff --git a/src/PowerPipe/Factories/PipelineStepFactory.cs b/src/PowerPipe/Factories/PipelineStepFactory.cs
index 0e8b20b..7d3b249 100644
--- a/src/PowerPipe/Factories/PipelineStepFactory.cs
+++ b/src/PowerPipe/Factories/PipelineStepFactory.cs
@@ -3,12 +3,11 @@
namespace PowerPipe.Factories;
-///
-/// Represents a factory for creating pipeline steps and compensation steps.
-///
+///
public class PipelineStepFactory : IPipelineStepFactory
{
- private readonly IServiceProvider _serviceProvider;
+ ///
+ public IServiceProvider ServiceProvider { get; }
///
/// Initializes a new instance of the class.
@@ -16,30 +15,20 @@ public class PipelineStepFactory : IPipelineStepFactory
/// The service provider to resolve step instances.
public PipelineStepFactory(IServiceProvider serviceProvider)
{
- _serviceProvider = serviceProvider;
+ ServiceProvider = serviceProvider;
}
- ///
- /// Creates an instance of a pipeline step.
- ///
- /// The type of step to create.
- /// The type of context used in the pipeline.
- /// An instance of the specified pipeline step.
+ ///
public IStepBase Create()
where TStep : IStepBase
{
- return _serviceProvider.GetService(typeof(TStep)) as IStepBase;
+ return ServiceProvider.GetService(typeof(TStep)) as IStepBase;
}
- ///
- /// Creates an instance of a pipeline compensation step.
- ///
- /// The type of compensation step to create.
- /// The type of context used in the pipeline.
- /// An instance of the specified pipeline compensation step.
+ ///
public IPipelineCompensationStep CreateCompensation()
where TStep : IPipelineCompensationStep
{
- return _serviceProvider.GetService(typeof(TStep)) as IPipelineCompensationStep;
+ return ServiceProvider.GetService(typeof(TStep)) as IPipelineCompensationStep;
}
-}
\ No newline at end of file
+}
diff --git a/src/PowerPipe/Interfaces/IPipelineStepFactory.cs b/src/PowerPipe/Interfaces/IPipelineStepFactory.cs
index edc4fac..1f8cba6 100644
--- a/src/PowerPipe/Interfaces/IPipelineStepFactory.cs
+++ b/src/PowerPipe/Interfaces/IPipelineStepFactory.cs
@@ -1,10 +1,17 @@
-namespace PowerPipe.Interfaces;
+using System;
+
+namespace PowerPipe.Interfaces;
///
/// Represents a factory for creating pipeline steps and compensation steps.
///
public interface IPipelineStepFactory
{
+ ///
+ /// Instance of the service provider
+ ///
+ IServiceProvider ServiceProvider { get; }
+
///
/// Creates an instance of a pipeline step.
///
@@ -22,4 +29,4 @@ IStepBase Create()
/// An instance of the specified pipeline compensation step.
IPipelineCompensationStep CreateCompensation()
where TStep : IPipelineCompensationStep;
-}
\ No newline at end of file
+}
diff --git a/src/PowerPipe/PowerPipe.csproj b/src/PowerPipe/PowerPipe.csproj
index d607836..2c7b5f3 100644
--- a/src/PowerPipe/PowerPipe.csproj
+++ b/src/PowerPipe/PowerPipe.csproj
@@ -8,4 +8,16 @@
+
+
+
+
+
+
+
+
+
+
+
+