-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* use disposableobject * implement async step * rename method * rename method * merge * to async pipeline * make beta * fix test * try fix
- Loading branch information
Showing
36 changed files
with
1,108 additions
and
444 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,23 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace AnakinRaW.CommonUtilities.SimplePipeline; | ||
|
||
/// <summary> | ||
/// Execution engine to run one or many <see cref="IStep"/>s. | ||
/// </summary> | ||
public interface IRunner : IEnumerable<IStep> | ||
public interface IRunner : IStepQueue, IDisposable | ||
{ | ||
/// <summary> | ||
/// Event which gets raised if the execution of an <see cref="IStep"/> failed with an exception. | ||
/// Gets raised when the execution of an <see cref="IStep"/> failed with an exception. | ||
/// </summary> | ||
event EventHandler<StepErrorEventArgs>? Error; | ||
|
||
/// <summary> | ||
/// Runs all queued steps | ||
/// Runs all queued steps. | ||
/// </summary> | ||
/// <param name="token">Provided <see cref="CancellationToken"/> to allow cancellation.</param> | ||
void Run(CancellationToken token); | ||
|
||
/// <summary> | ||
/// Queues an <see cref="IStep"/> for execution. | ||
/// </summary> | ||
/// <param name="activity">The step to queue.</param> | ||
void Queue(IStep activity); | ||
/// <param name="token">The cancellation token, allowing the runner to cancel the operation.</param> | ||
/// <returns>A task that represents the completion of the operation.</returns> | ||
Task RunAsync(CancellationToken token); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace AnakinRaW.CommonUtilities.SimplePipeline; | ||
|
||
/// <summary> | ||
/// A queue of <see cref="IStep"/>. | ||
/// </summary> | ||
public interface IStepQueue | ||
{ | ||
/// <summary> | ||
/// List of only those steps which are scheduled for execution of an <see cref="IRunner"/>. | ||
/// </summary> | ||
public IReadOnlyList<IStep> Steps { get; } | ||
|
||
/// <summary> | ||
/// Adds an <see cref="IStep"/> to the <see cref="IRunner"/>. | ||
/// </summary> | ||
/// <param name="activity">The step to app.</param> | ||
void AddStep(IStep activity); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 8 additions & 6 deletions
14
src/CommonUtilities.SimplePipeline/src/Pipelines/IPipeline.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,29 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace AnakinRaW.CommonUtilities.SimplePipeline; | ||
|
||
/// <summary> | ||
/// A pipeline can run multiple operations in sequence or simultaneously, based on how it was prepared. | ||
/// </summary> | ||
public interface IPipeline : IDisposable | ||
{ | ||
{ | ||
/// <summary> | ||
/// Prepares this instance for execution. | ||
/// </summary> | ||
/// <remarks> | ||
/// Preparation can only be done once per instance. | ||
/// </remarks> | ||
/// <returns><see langword="true"/> if the preparation was successful; <see langword="false"/> otherwise.</returns> | ||
bool Prepare(); | ||
|
||
/// <returns>A task that represents whether the preparation was successful.</returns> | ||
Task<bool> PrepareAsync(); | ||
/// <summary> | ||
/// Runs pipeline. | ||
/// Runs pipeline synchronously. | ||
/// </summary> | ||
/// <param name="token">Provided <see cref="CancellationToken"/> to allow cancellation.</param> | ||
/// <returns>A task that represents the operation completion.</returns> | ||
/// <exception cref="OperationCanceledException">If <paramref name="token"/> was requested for cancellation.</exception> | ||
/// <exception cref="StepFailureException">The pipeline may throw this exception if one or many steps failed.</exception> | ||
void Run(CancellationToken token = default); | ||
Task RunAsync(CancellationToken token = default); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
src/CommonUtilities.SimplePipeline/src/Pipelines/ParallelProducerConsumerPipeline.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using AnakinRaW.CommonUtilities.SimplePipeline.Runners; | ||
|
||
namespace AnakinRaW.CommonUtilities.SimplePipeline; | ||
|
||
/// <summary> | ||
/// A simple pipeline that runs all steps on the thread pool in parallel. Allows to run the pipeline even if preparation is not completed. | ||
/// </summary> | ||
/// <remarks> | ||
/// Useful, if preparation is work intensive. | ||
/// </remarks> | ||
public abstract class ParallelProducerConsumerPipeline : DisposableObject, IPipeline | ||
{ | ||
private readonly bool _failFast; | ||
private CancellationTokenSource? _linkedCancellationTokenSource; | ||
private readonly ParallelProducerConsumerRunner _runner; | ||
|
||
private bool? _prepareSuccessful; | ||
|
||
/// <summary> | ||
/// Gets or sets a value indicating whether the pipeline has encountered a failure. | ||
/// </summary> | ||
protected bool PipelineFailed { get; set; } | ||
|
||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="ParallelProducerConsumerPipeline"/> class. | ||
/// </summary> | ||
/// <param name="serviceProvider">The service provider for dependency injection within the pipeline.</param> | ||
/// <param name="workerCount">The number of worker threads to be used for parallel execution.</param> | ||
/// <param name="failFast">A value indicating whether the pipeline should fail fast.</param> | ||
protected ParallelProducerConsumerPipeline(IServiceProvider serviceProvider, int workerCount = 4, bool failFast = true) | ||
{ | ||
_failFast = failFast; | ||
_runner = new ParallelProducerConsumerRunner(workerCount, serviceProvider); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public async Task<bool> PrepareAsync() | ||
{ | ||
ThrowIfDisposed(); | ||
if (_prepareSuccessful.HasValue) | ||
return _prepareSuccessful.Value; | ||
|
||
await BuildSteps(_runner).ConfigureAwait(false); | ||
|
||
_prepareSuccessful = true; | ||
return _prepareSuccessful.Value; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public async Task RunAsync(CancellationToken token = default) | ||
{ | ||
ThrowIfDisposed(); | ||
token.ThrowIfCancellationRequested(); | ||
|
||
if (_prepareSuccessful is false) | ||
return; | ||
|
||
try | ||
{ | ||
_linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token); | ||
|
||
if (_prepareSuccessful is null) | ||
{ | ||
Task.Run(async () => | ||
{ | ||
try | ||
{ | ||
var result = await PrepareAsync().ConfigureAwait(false); | ||
if (!result) | ||
_linkedCancellationTokenSource?.Cancel(); | ||
} | ||
finally | ||
{ | ||
_runner.Finish(); | ||
} | ||
}, token).Forget(); | ||
} | ||
|
||
|
||
|
||
_runner.Error += OnError; | ||
await _runner.RunAsync(_linkedCancellationTokenSource.Token).ConfigureAwait(false); | ||
} | ||
finally | ||
{ | ||
_runner.Error -= OnError; | ||
if (_linkedCancellationTokenSource is not null) | ||
{ | ||
_linkedCancellationTokenSource.Dispose(); | ||
_linkedCancellationTokenSource = null; | ||
} | ||
} | ||
|
||
if (!PipelineFailed && _prepareSuccessful.HasValue && _prepareSuccessful.Value) | ||
return; | ||
|
||
if (_prepareSuccessful is not true) | ||
throw new InvalidOperationException("Preparation of the pipeline failed."); | ||
|
||
var failedBuildSteps = _runner.Steps | ||
.Where(p => p.Error != null && !p.Error.IsExceptionType<OperationCanceledException>()) | ||
.ToList(); | ||
|
||
if (failedBuildSteps.Any()) | ||
throw new StepFailureException(failedBuildSteps); | ||
} | ||
|
||
/// <summary> | ||
/// Builds the steps in the order they should be executed within the pipeline. | ||
/// </summary> | ||
/// <returns>A list of steps in the order they should be executed.</returns> | ||
protected abstract Task BuildSteps(IStepQueue queue); | ||
|
||
/// <summary> | ||
/// Called when an error occurs within a step. | ||
/// </summary> | ||
/// <param name="sender">The sender of the event.</param> | ||
/// <param name="e">The event arguments.</param> | ||
protected virtual void OnError(object sender, StepErrorEventArgs e) | ||
{ | ||
PipelineFailed = true; | ||
if (_failFast || e.Cancel) | ||
_linkedCancellationTokenSource?.Cancel(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.