diff --git a/README.md b/README.md index 5d87eb3..f46ee7f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ## Table of Contents -- [What's new - previous versions]() +- [What's new - previous versions](./docs/whatsnewprev.md) - [Features](#features) - [Installing](#installing) - [Examples](#examples) @@ -28,23 +28,38 @@ - [API Reference](https://fracerqueira.github.io/PipeAndFilter/apis/apis.html) ## What's new in the latest version -### V1.0.1 +### V1.0.2 [**Top**](#table-of-contents) -- First Release G.A +- Added ability to save/overwrite multiple result to use during the execution another pipe / aggregation pipe + - Removed propery 'SavedTasks' in EventPipe + - Removed propery 'SavedPipes' in EventPipe + - Removed Method 'SaveValue' + - Removed Method 'RemoveSavedValue' + - Added Method TrySavedValue + - Now TrySavedValue return true/false if exist id saved and value in out paramameter + - Added Method SaveValueAtEnd + - Now SaveValueAtEnd receives the unique id to be saved/overwrite and the value + - Added Method RemoveValueAtEnd + - Now RemoveValueAtEnd receives the unique id to be removed if any +- Added ability to multiple preconditions for Tasks + - Channged command AddTaskCondition + - Now the same parameters as AddTask + - Added command WithCondition for AddTaskCondition ## Features [**Top**](#table-of-contents) -- Contract with thread safety for change values +- Thread safety to obtain/change contract values ​​and/or generic purpose when running a Task (pararel execute) +- Add multiple pipe +- Add multiple agregate pipe (for run pararel tasks) - Set the maximum amount of parallel execution -- Add multiple preconditions to run a pipe +- Add multiple preconditions to run a pipe or task - Add multiple link to the pipe to jump to another pipe -- Add tasks with a precondition - Have detailed status (execution date, execution time, type of execution, result of each execution) and number of executions in each pipe -- Save a result from each pipe to use when executing another pipe -- Save a result from each task to use during the execution of the aggregation pipe +- Save multiple results from each pipe to be used during the another pipe/aggregate pipe run +- Save multiple results in each task to be effective during the aggregation pipe run - Terminate the PipeAndFilter on any task, condition or pipe - Simple and clear fluent syntax @@ -78,20 +93,22 @@ The **PipeAndFilter** use **fluent interface**; an object-oriented API whose des ### Sample-Console Usage ```csharp -var result = await PipeAndFilter.New() - .AddPipe(ExecPipe1) - .WithGotoCondition(CondFalse, "LastPipe") - .WithCondition(CondTrue) - .WithCondition(CondTrue) - .AddPipe(ExecPipe2) - .AddPipe(ExecPipe3) - .AddPipeTasks(AgregateTask) - .WithCondition(CondTrue) +await PipeAndFilter.New() + .AddPipe(Pipe1) + .WithGotoCondition(Cond0, "LastPipe") + .WithCondition(Cond1) + .WithCondition(Cond2) + .AddPipe(Pipe2) + .AddPipe(Pipe3) + .AddPipeTasks(Pipe4) + .WithCondition(Cond1) .MaxDegreeProcess(4) - .AddTask(Task1) - .AddTaskCondition(Task2, CondFalse) - .AddTask(Task3) - .AddPipe(ExecPipe5, "LastPipe") + .AddTask(Task50) + .AddTaskCondition(Task100) + .WithCondition(Cond3) + .WithCondition(Cond4) + .AddTask(Task150) + .AddPipe(Pipe5, "LastPipe") .BuildAndCreate() .Init(contract) .CorrelationId(null) @@ -105,12 +122,12 @@ var result = await PipeAndFilter.New() ```csharp builder.Services .AddPipeAndFilter(PipeAndFilter.New() - .AddPipe(ExecPipe) + .AddPipe(TemperatureAdd10) .Build()); ``` ```csharp -private static Task ExecPipe(EventPipe pipe, CancellationToken token) +private static Task TemperatureAdd10(EventPipe pipe, CancellationToken token) { pipe.ThreadSafeAccess((contract) => { @@ -126,9 +143,9 @@ private static Task ExecPipe(EventPipe pipe, CancellationToken public class WeatherForecastController : ControllerBase { private readonly ILogger _logger; - private readonly IPipeAndFilterServiceBuild _mypipe; + private readonly IPipeAndFilterService _mypipe; - public WeatherForecastController(ILogger logger, IPipeAndFilterServiceBuild pipeAndFilter) + public WeatherForecastController(ILogger logger, IPipeAndFilterService pipeAndFilter) { _logger = logger; _mypipes = pipeAndFilter; @@ -158,65 +175,26 @@ All pipes, conditions and tasks do not perform any task, they are only called an See folder [**Samples/PipeandFIlterBenchmarking**](https://github.com/FRACerqueira/PipeAndFilter/tree/main/Samples/PipeandFIlterBenchmarking). ``` -BenchmarkDotNet v0.13.10, Windows 10 (10.0.19044.3570/21H2/November2021Update) -Intel Core i7-8565U CPU 1.80GHz (Whiskey Lake), 1 CPU, 8 logical and 4 physical cores -.NET SDK 8.0.100-rc.2.23502.2 - [Host] : .NET 8.0.0 (8.0.23.47906), X64 RyuJIT AVX2 - DefaultJob : .NET 8.0.0 (8.0.23.47906), X64 RyuJIT AVX2 -``` - -| Method | Mean | Error | StdDev | Median | Gen0 | Allocated | -|----------------------------- |-----------:|-----------:|-----------:|-----------:|--------:|----------:| -| PipeAsync | 7.419 us | 0.1483 us | 0.3347 us | 7.345 us | 1.1597 | 4.74 KB | -| PipeWith10Async | 239.257 us | 10.6802 us | 30.9852 us | 234.596 us | 19.5313 | 80.68 KB | -| PipeWithConditionAsync | 8.273 us | 0.1639 us | 0.2599 us | 8.146 us | 1.4038 | 5.76 KB | -| PipeWith10ConditionAsync | 20.606 us | 0.4113 us | 0.9774 us | 20.202 us | 3.6011 | 14.78 KB | -| PipeWith10ConditionGotoAsync | 33.396 us | 0.6631 us | 1.2455 us | 33.024 us | 5.1270 | 21.08 KB | -| PipeTaskAsync | 16.918 us | 0.5232 us | 1.5096 us | 16.795 us | 1.7090 | 7.07 KB | -| PipeWith10TaskAsync | 72.402 us | 3.5790 us | 9.8577 us | 68.424 us | 4.8828 | 20.47 KB | -| PipeTaskConditionAsync | 19.375 us | 0.3853 us | 0.9736 us | 19.425 us | 1.8616 | 7.66 KB | -| PipeWith10TaskConditionAsync | 63.898 us | 1.2774 us | 2.9858 us | 63.562 us | 4.8828 | 20.47 KB | - -``` +------------------------------------------------------------------------------------------------------ BenchmarkDotNet v0.13.10, Windows 10 (10.0.19044.3570/21H2/November2021Update) Intel Core i7-8565U CPU 1.80GHz (Whiskey Lake), 1 CPU, 8 logical and 4 physical cores .NET SDK 8.0.100-rc.2.23502.2 [Host] : .NET 7.0.13 (7.0.1323.51816), X64 RyuJIT AVX2 DefaultJob : .NET 7.0.13 (7.0.1323.51816), X64 RyuJIT AVX2 +------------------------------------------------------------------------------------------------------ +| Method | Mean | Error | StdDev | Median | Gen0 | Allocated | +|----------------------------- |----------:|----------:|----------:|----------:|--------:|----------:| +| PipeAsync | 3.990 us | 0.0460 us | 0.0384 us | 3.992 us | 0.8698 | 3.57 KB | +| PipeWith10Async | 97.574 us | 1.7283 us | 1.7748 us | 97.153 us | 15.0146 | 61.37 KB | +| PipeWithConditionAsync | 5.003 us | 0.0591 us | 0.0524 us | 5.003 us | 1.0834 | 4.45 KB | +| PipeWith10ConditionAsync | 13.157 us | 0.1262 us | 0.0985 us | 13.155 us | 3.1891 | 13.05 KB | +| PipeWith10ConditionGotoAsync | 18.253 us | 0.3007 us | 0.2347 us | 18.211 us | 3.9978 | 16.34 KB | +| PipeTaskAsync | 9.741 us | 0.1923 us | 0.3517 us | 9.649 us | 1.3275 | 5.45 KB | +| PipeWith10TaskAsync | 45.064 us | 0.7313 us | 0.8981 us | 44.984 us | 4.5166 | 18.58 KB | +| PipeTaskConditionAsync | 11.280 us | 0.1956 us | 0.1830 us | 11.312 us | 1.5564 | 6.39 KB | +| PipeWith10TaskConditionAsync | 48.034 us | 0.9578 us | 2.5895 us | 47.222 us | 4.5166 | 18.58 KB | ``` -| Method | Mean | Error | StdDev | Median | Gen0 | Allocated | -|----------------------------- |-----------:|----------:|-----------:|-----------:|--------:|----------:| -| PipeAsync | 11.231 μs | 0.4573 μs | 1.3195 μs | 10.898 μs | 1.1597 | 4.79 KB | -| PipeWith10Async | 226.285 μs | 4.5187 μs | 10.8264 μs | 222.330 μs | 19.5313 | 80.73 KB | -| PipeWithConditionAsync | 9.902 μs | 0.1137 μs | 0.0950 μs | 9.858 μs | 1.4038 | 5.8 KB | -| PipeWith10ConditionAsync | 26.949 μs | 0.9860 μs | 2.6824 μs | 26.154 μs | 3.6011 | 14.83 KB | -| PipeWith10ConditionGotoAsync | 39.820 μs | 0.7613 μs | 1.2075 μs | 39.498 μs | 5.1270 | 21.13 KB | -| PipeTaskAsync | 20.286 μs | 0.6041 μs | 1.7334 μs | 19.744 μs | 1.7395 | 7.12 KB | -| PipeWith10TaskAsync | 101.252 μs | 5.3239 μs | 15.4455 μs | 97.842 μs | 4.8828 | 20.53 KB | -| PipeTaskConditionAsync | 24.214 μs | 1.3098 μs | 3.7998 μs | 22.740 μs | 1.8616 | 7.7 KB | -| PipeWith10TaskConditionAsync | 98.953 μs | 3.9903 μs | 11.0570 μs | 95.221 μs | 4.8828 | 20.56 KB | - -``` -BenchmarkDotNet v0.13.10, Windows 10 (10.0.19044.3570/21H2/November2021Update) -Intel Core i7-8565U CPU 1.80GHz (Whiskey Lake), 1 CPU, 8 logical and 4 physical cores -.NET SDK 8.0.100-rc.2.23502.2 - [Host] : .NET Core 3.1.32 (CoreCLR 4.700.22.55902, CoreFX 4.700.22.56512), X64 RyuJIT AVX2 - DefaultJob : .NET Core 3.1.32 (CoreCLR 4.700.22.55902, CoreFX 4.700.22.56512), X64 RyuJIT AVX2 -``` - -| Method | Mean | Error | StdDev | Gen0 | Allocated | -|----------------------------- |----------:|---------:|---------:|--------:|----------:| -| PipeAsync | 14.38 us | 0.225 us | 0.199 us | 1.1597 | 4.77 KB | -| PipeWith10Async | 328.18 us | 6.287 us | 5.880 us | 19.5313 | 81.7 KB | -| PipeWithConditionAsync | 17.11 us | 0.283 us | 0.237 us | 1.4038 | 5.85 KB | -| PipeWith10ConditionAsync | 36.82 us | 0.702 us | 0.657 us | 3.6621 | 15.44 KB | -| PipeWith10ConditionGotoAsync | 58.69 us | 1.103 us | 2.557 us | 5.3101 | 21.8 KB | -| PipeTaskAsync | 37.06 us | 0.720 us | 1.077 us | 1.7090 | 7.18 KB | -| PipeWith10TaskAsync | 222.57 us | 2.935 us | 2.745 us | 4.8828 | 20.52 KB | -| PipeTaskConditionAsync | 42.97 us | 0.906 us | 2.525 us | 1.8921 | 7.84 KB | -| PipeWith10TaskConditionAsync | 224.77 us | 2.119 us | 1.982 us | 4.8828 | 20.54 KB | - ## Code of Conduct [**Top**](#table-of-contents) diff --git a/Samples/PipeandFIlterBenchmarking/MemoryBenchmarkerDemo.cs b/Samples/PipeandFIlterBenchmarking/MemoryBenchmarkerDemo.cs index 74adf42..e6f7f0a 100644 --- a/Samples/PipeandFIlterBenchmarking/MemoryBenchmarkerDemo.cs +++ b/Samples/PipeandFIlterBenchmarking/MemoryBenchmarkerDemo.cs @@ -102,7 +102,8 @@ public async Task PipeTaskConditionAsync() { await PipeAndFilter.New() .AddPipeTasks(ExecPipe) - .AddTaskCondition(ExecTask,CondTrue) + .AddTaskCondition(ExecTask) + .WithCondition(CondTrue) .BuildAndCreate() .Run(); } diff --git a/Samples/SampleConsole/Program.cs b/Samples/SampleConsole/Program.cs index 26b528e..009d651 100644 --- a/Samples/SampleConsole/Program.cs +++ b/Samples/SampleConsole/Program.cs @@ -1,4 +1,5 @@ -using PipeFilterCore; +using System.Diagnostics.Contracts; +using PipeFilterCore; namespace PipeFilterCoreSamples { @@ -23,7 +24,9 @@ public static async Task Main() .WithCondition(CondTrue) .MaxDegreeProcess(4) .AddTask(Task50) - .AddTaskCondition(Task100, CondFalse) + .AddTaskCondition(Task100) + .WithCondition(CondTrue) + .WithCondition(CondFalse) .AddTask(Task150) .AddPipe(ExecPipe, "LastPipe") .BuildAndCreate() @@ -32,13 +35,13 @@ public static async Task Main() .Logger(null) .Run(); - Console.WriteLine($"Contract value : {contract.MyProperty} Total Elapsedtime: {pl.Elapsedtime}" ); + Console.WriteLine($"Contract value : {contract.MyProperty} Total Elapsedtime: {pl.Elapsedtime}"); foreach (var item in pl.Status) { Console.WriteLine($"{item.Alias}:{item.Status.Value} Count: {item.Count} => {item.Status.Elapsedtime}"); - foreach (var det in item.StatusDetails) + foreach (var det in item.StatusDetails) { - Console.WriteLine($"\t{det.TypeExec}:{det.GotoAlias ?? det.Alias}:{det.Condition} => {det.Value}:{det.Elapsedtime} UTC:{det.DateRef.ToString("MM/dd/yyyy hh:mm:ss ffff")}"); + Console.WriteLine($"\t{det.TypeExec}:{det.GotoAlias ?? det.Alias}:{det.Condition} => {det.Value}:{det.Elapsedtime} UTC:{det.DateRef:MM/dd/yyyy hh:mm:ss ffff}"); } } @@ -57,7 +60,7 @@ private static async Task Task50(EventPipe pipe, CancellationToken toke try { await Task.Delay(50, token); - pipe.SaveValue(50); + pipe.SaveValueAtEnd("T50",50); } catch (TaskCanceledException) { @@ -74,7 +77,7 @@ private static async Task Task100(EventPipe pipe, CancellationToken tok try { await Task.Delay(100, token); - pipe.SaveValue(100); + pipe.SaveValueAtEnd("T100",100); } catch (TaskCanceledException) { @@ -91,7 +94,7 @@ private static async Task Task150(EventPipe pipe, CancellationToken tok try { await Task.Delay(150, token); - pipe.SaveValue(150); + pipe.SaveValueAtEnd("T150",150); } catch (TaskCanceledException) { @@ -101,7 +104,7 @@ private static async Task Task150(EventPipe pipe, CancellationToken tok private static Task ExecPipe(EventPipe pipe, CancellationToken token) { - pipe.SaveValue("Saved"); + pipe.SaveValueAtEnd("ExecPipe", "Saved1"); return Task.CompletedTask; } @@ -112,7 +115,7 @@ private static Task AgregateTask(EventPipe pipe, CancellationToken toke private static async Task ExecPipe100(EventPipe pipe, CancellationToken token) { - pipe.SaveValue("Saved0"); + pipe.SaveValueAtEnd("ExecPipe100", "Saved2"); try { await Task.Delay(100, token); diff --git a/Src/CommandsInterface/IPipeAndFilterTaskCondition.cs b/Src/CommandsInterface/IPipeAndFilterTaskCondition.cs new file mode 100644 index 0000000..39abb35 --- /dev/null +++ b/Src/CommandsInterface/IPipeAndFilterTaskCondition.cs @@ -0,0 +1,58 @@ +// ******************************************************************************************** +// MIT LICENCE +// The maintenance and evolution is maintained by the PipeAndFilter project under MIT license +// ******************************************************************************************** + +namespace PipeFilterCore +{ + /// + /// Represents commands for conditions. + /// + /// Type of contract. + public interface IPipeAndFilterTaskCondition: IPipeAndFilterBuild where T : class + { + /// + /// Add new pipe. + /// + /// The handler pipe to execute. + /// + /// The unique alias for pipe. + ///
If the alias is omitted, the alias will be the handler name followed by the reference quantity (if any).
+ ///
Alias ​​is used to reference in another pipe.
+ /// + /// + IPipeAndFilterAdd AddPipe(Func, CancellationToken, Task> command, string? alias = null); + + /// + /// Add new pipe aggregate tasks. + /// + /// The handler pipe aggregate to execute. + ///
The handler command will run after all tasks are executed.
+ /// + /// + /// The unique alias for pipe. + ///
If the alias is omitted, the alias will be the handler name followed by the reference quantity (if any).
+ ///
Alias ​​is used to reference in another pipe.
+ /// + /// + IPipeAndFilterTasks AddPipeTasks(Func, CancellationToken, Task> command, string? alias = null); + + + /// + /// Add new task (execution in parallel) through pipe. + /// + /// The handler task to execute. + /// The name for task (optional). + /// + IPipeAndFilterTasks AddTask(Func, CancellationToken, Task> command, string? nametask = null); + + /// + /// Add new condition for task. + /// + /// The handle condition to execute. + /// The name for condition(optional). + /// + IPipeAndFilterTaskCondition WithCondition(Func, CancellationToken, ValueTask> condition, string? namecondition = null); + } + +} diff --git a/Src/CommandsInterface/IPipeAndFilterTasks.cs b/Src/CommandsInterface/IPipeAndFilterTasks.cs index 66fe851..93da457 100644 --- a/Src/CommandsInterface/IPipeAndFilterTasks.cs +++ b/Src/CommandsInterface/IPipeAndFilterTasks.cs @@ -57,14 +57,12 @@ public interface IPipeAndFilterTasks: IPipeAndFilterBuild where T : class /// - /// Add new task (execution in parallel) through pipe with a condition. + /// Add new task (execution in parallel) through pipe with conditions. /// /// The handler task to execute. - /// The handler task to condition. /// The name for task (optional). - /// The name for condition (optional). - /// - IPipeAndFilterTasks AddTaskCondition(Func, CancellationToken, Task> command, Func, CancellationToken, ValueTask> condition, string? nametask = null, string? namecondition = null); + /// + IPipeAndFilterTaskCondition AddTaskCondition(Func, CancellationToken, Task> command, string? nametask = null); /// /// Add new condition. diff --git a/Src/CommandsInterface/internal/IPipeAndFilterOptions.cs b/Src/CommandsInterface/internal/IPipeAndFilterOptions.cs index caea89b..ea27604 100644 --- a/Src/CommandsInterface/internal/IPipeAndFilterOptions.cs +++ b/Src/CommandsInterface/internal/IPipeAndFilterOptions.cs @@ -11,12 +11,8 @@ namespace PipeFilterCore internal interface IPipeAndFilterOptions where T : class { string? ServiceId { get; } - IImmutableDictionary AliasToId { get; } - IImmutableDictionary IdToAlias { get; } - IImmutableDictionary MaxDegreeProcess { get; } - IImmutableList> Pipes { get; } - IImmutableDictionary AggregateTasks { get; } - IImmutableDictionary>> PreConditions { get; } - IImmutableDictionary>> Tasks { get; } + ImmutableDictionary AliasToId { get; } + ImmutableDictionary IdToAlias { get; } + ImmutableList> Pipes { get; } } } diff --git a/Src/Control/EventPipe.cs b/Src/Control/EventPipe.cs index 350f7a7..6366f61 100644 --- a/Src/Control/EventPipe.cs +++ b/Src/Control/EventPipe.cs @@ -16,6 +16,8 @@ namespace PipeFilterCore public class EventPipe where T : class { private readonly Action> _changecontract; + private readonly List<(string id,string? value, bool toremove)> _toSaveRemove = new(); + private readonly ImmutableDictionary _savedvalues; /// /// Create Event-Pipe. @@ -35,19 +37,17 @@ private EventPipe() /// The correlation Id. /// Handle of log. /// Handle of changecontract. - /// The values saved by pipe. - /// The values saved by tasks. + /// The values saved. /// The previous Id. /// The current Id. /// The previous alias. /// The current alias. - public EventPipe(string? cid, ILogger logger, Action> changecontract, ImmutableArray<(string? Alias, string Id,string? Result)> savedpipes, ImmutableArray<(string? Alias, string Id, string? Result)> savedtasks, string? fromId, string currentId, string? fromAlias, string? currentAlias) + public EventPipe(string? cid, ILogger logger, Action> changecontract, ImmutableDictionary savedvalues, string? fromId, string currentId, string? fromAlias, string? currentAlias) { _changecontract = changecontract; CorrelationId = cid; - Logger = logger; - SavedPipes = savedpipes; - SavedTasks = savedtasks; + Logger = logger; + _savedvalues = savedvalues; FromAlias = fromAlias; FromId = fromId; CurrentAlias = currentAlias; @@ -55,19 +55,27 @@ public EventPipe(string? cid, ILogger logger, Action> changecontract, } /// - /// The values saved ​​associated with pipes. + /// Try get value saved ​​associated with a unique key. ///
The values ​​are serialized in json.
///
Null result may exist.
///
- public ImmutableArray<(string? Alias, string Id, string? Result)> SavedPipes { get; } - - /// - /// The values saved ​​associated with tasks. - ///
Data only exists when executed by an aggregator pipe.
- ///
The values ​​are serialized in json.
- ///
Null result may exist.
- ///
- public ImmutableArray<(string? Alias, string Id, string? Result)> SavedTasks { get; } + /// + /// The unique key Id. + /// + /// + /// The value saved if any. + /// + /// True if value exists, otherwise false with null value + public bool TrySavedValue(string id, out string? value) + { + if (id == null) + { + throw new PipeAndFilterException( + PipeAndFilterException.StatusInit, + "id cannot be null"); + } + return _savedvalues.TryGetValue(id, out value); + } /// /// The current Alias. @@ -113,34 +121,53 @@ public void ThreadSafeAccess(Action action) } /// - /// Save/overwrite a value associated with this pipe or task. + /// Save/replace a value associated with a unique key at the end of this event(If this event is not a task event). + ///
Values ​​saved in the task event will only take effect in the pipe aggregation event
+ ///
A task event cannot see values ​​saved and/or removed by another task.
+ ///
In a task event, Never try to overwrite a value already saved by another event, the results may not be as expected as the execution sequence is not guaranteed.
///
The values ​​will serialize into json.
///
/// Type value to save. + /// + /// The unique key Id. + /// /// /// The value to save. /// - public void SaveValue(T1 value) + public void SaveValueAtEnd(string id, T1 value) { - IsSaved = true; - ToRemove = false; - ValueToSave = JsonSerializer.Serialize(value); + if (id == null) + { + throw new PipeAndFilterException( + PipeAndFilterException.StatusInit, + "id cannot be null"); + } + _toSaveRemove.Add((id, JsonSerializer.Serialize(value), false)); } /// - /// Remove a value associated with this pipe or task. + /// Remove a value associated with a unique key at the end of this event (If this event is not a task event). + ///
Values ​​removed in the task event will only take effect in the pipe aggregation event
+ ///
A task event cannot see values ​​saved and/or removed by another task.
+ ///
In a task event, Never try to overwrite a value already saved by another event, the results may not be as expected as the execution sequence is not guaranteed.
///
- public void RemoveSavedValue() + /// + /// The unique key Id. + /// + public void RemoValueAtEnd(string id) { - IsSaved = false; - ToRemove = true; + if (id == null) + { + throw new PipeAndFilterException( + PipeAndFilterException.StatusInit, + "id cannot be null"); + } + _toSaveRemove.Add((id, null, true)); } internal string CurrentId { get; } internal string? FromId { get; } internal bool FinishedPipeAndFilter { get; set; } - internal bool ToRemove { get; set; } - internal bool IsSaved { get; set; } - internal string? ValueToSave { get; set; } + internal IEnumerable<(string id, string? value, bool toremove)> ToSaveRemove => _toSaveRemove; } } \ No newline at end of file diff --git a/Src/Control/internal/PipeAndFilterBuild.cs b/Src/Control/internal/PipeAndFilterBuild.cs index 277a428..ef4b2a3 100644 --- a/Src/Control/internal/PipeAndFilterBuild.cs +++ b/Src/Control/internal/PipeAndFilterBuild.cs @@ -17,18 +17,15 @@ internal class PipeAndFilterBuild : IPipeAndFilterAdd, IPipeAndFilterCondition, IPipeAndFilterTasks, + IPipeAndFilterTaskCondition, IPipeAndFilterOptions where T : class { private readonly Dictionary _aliasToId = new(); private readonly Dictionary _idToAlias = new(); - private readonly Dictionary _maxDegreeProcess = new(); private readonly List> _pipes = new(); - private readonly Dictionary _aggregateTasks = new(); - private readonly Dictionary>> _precondhandler = new(); - private readonly Dictionary>> _tasks = new(); - private readonly int _defaultMaxProcess = Environment.ProcessorCount; private string? _currentPipe; + private string? _currentTask; private string? _serviceId; @@ -36,33 +33,11 @@ internal class PipeAndFilterBuild : public string? ServiceId => _serviceId; - public IImmutableDictionary AliasToId => _aliasToId.ToImmutableDictionary(); + public ImmutableDictionary AliasToId => _aliasToId.ToImmutableDictionary(); - public IImmutableDictionary IdToAlias => _idToAlias.ToImmutableDictionary(); + public ImmutableDictionary IdToAlias => _idToAlias.ToImmutableDictionary(); - public IImmutableDictionary MaxDegreeProcess => _maxDegreeProcess.ToImmutableDictionary(); - - public IImmutableList> Pipes => _pipes.ToImmutableList(); - - public IImmutableDictionary AggregateTasks => _aggregateTasks.ToImmutableDictionary(); - - public IImmutableDictionary>> PreConditions - { - get - { - return ImmutableDictionary - .CreateRange(_precondhandler.Select(obj => new KeyValuePair>>(obj.Key, obj.Value.ToImmutableList()))); - } - } - - public IImmutableDictionary>> Tasks - { - get - { - return ImmutableDictionary - .CreateRange(_tasks.Select(obj => new KeyValuePair>>(obj.Key, obj.Value.ToImmutableList()))); - } - } + public ImmutableList> Pipes => _pipes.ToImmutableList(); #endregion @@ -154,13 +129,13 @@ IPipeAndFilterCondition IPipeAndFilterCondition.WithGotoCondition(Func IPipeAndFilterTasks.AddTask(Func, CancellationToken, Task> command, string? nametask) { - SharedAddTask(command, null, nametask, null); + SharedAddTask(command, nametask); return this; } - IPipeAndFilterTasks IPipeAndFilterTasks.AddTaskCondition(Func, CancellationToken, Task> command, Func, CancellationToken, ValueTask> condition, string? nametask, string? namecondition) + IPipeAndFilterTaskCondition IPipeAndFilterTasks.AddTaskCondition(Func, CancellationToken, Task> command, string? nametask) { - SharedAddTask(command, condition, nametask, namecondition); + SharedAddTask(command, nametask); return this; } @@ -178,19 +153,14 @@ IPipeAndFilterTasks IPipeAndFilterTasks.MaxDegreeProcess(int value) PipeAndFilterException.StatusInit, "Pipe found to set MaxDegreeProcess"); } - if (!_aggregateTasks.TryGetValue(_currentPipe!, out _)) + var index = _pipes.FindIndex(x => x.Id == _currentPipe! && x.IsAgregate); + if (index < 0) { throw new PipeAndFilterException( PipeAndFilterException.StatusInit, "Pipe not aggregate tasks"); } - if (!_maxDegreeProcess.TryGetValue(_currentPipe!, out _)) - { - throw new PipeAndFilterException( - PipeAndFilterException.StatusInit, - "Pipe not found to set MaxDegreeProcess"); - } - _maxDegreeProcess[_currentPipe!] = value; + _pipes[index].MaxDegreeProcess = value; return this; } @@ -227,6 +197,46 @@ IPipeAndFilterTasks IPipeAndFilterTasks.AddPipeTasks(Func, Ca #endregion + #region IPipeAndFilterTaskCondition + + IPipeAndFilterAdd IPipeAndFilterTaskCondition.AddPipe(Func, CancellationToken, Task> command, string? alias) + { + SharedAddPipeTasks(command, alias, false); + return this; + } + + IPipeAndFilterTasks IPipeAndFilterTaskCondition.AddPipeTasks(Func, CancellationToken, Task> command, string? alias) + { + SharedAddPipeTasks(command, alias, true); + return this; + } + + IPipeAndFilterTasks IPipeAndFilterTaskCondition.AddTask(Func, CancellationToken, Task> command, string? nametask) + { + SharedAddTask(command, nametask); + return this; + } + + IPipeAndFilterTaskCondition IPipeAndFilterTaskCondition.WithCondition(Func, CancellationToken, ValueTask> condition, string? namecondition) + { + if (string.IsNullOrEmpty(_currentTask)) + { + throw new PipeAndFilterException( + PipeAndFilterException.StatusInit, + "Task not exist to add WithCondition"); + } + if (string.IsNullOrEmpty(namecondition)) + { + namecondition = condition.Method.Name; + } + var index = _pipes.FindIndex(x => x.Id == _currentPipe! && x.IsAgregate); + var indextask = _pipes[index].Tasks.FindIndex(x => x.Id == _currentTask!); + _pipes[index].Tasks[indextask].Condtitions.Add(new PreCondition(condition, null, namecondition)); + return this; + } + + #endregion + #region IPipeAndFilterBuild IPipeAndFilterService IPipeAndFilterBuild.Build(string? serviceId) @@ -238,9 +248,10 @@ IPipeAndFilterService IPipeAndFilterBuild.Build(string? serviceId) PipeAndFilterException.StatusInit, "Not pipes to run"); } - foreach (var item in _precondhandler) + + foreach (var item in _pipes) { - foreach (var precond in item.Value.Where(x => !string.IsNullOrEmpty(x.GotoId))) + foreach (var precond in item.Condtitions.Where(x => !string.IsNullOrEmpty(x.GotoId))) { var id = _aliasToId[precond.GotoId!]; if (!_pipes.Any(x => x.Id == id)) @@ -294,37 +305,12 @@ private void SharedAddPipeTasks(Func, CancellationToken, Task> comm PipeAndFilterException.StatusInit, "pipe already exists"); } - if (agregatetask) - { - _maxDegreeProcess.Add(id, _defaultMaxProcess); - } - if (_pipes.Any(x => x.Id == id)) - { - throw new PipeAndFilterException( - PipeAndFilterException.StatusInit, - "idpipe already exists"); - } - _pipes.Add(new PipeCommand(id, command)); - if (!_aggregateTasks.TryAdd(id, agregatetask)) - { - throw new PipeAndFilterException( - PipeAndFilterException.StatusInit, - "idpipe already exists"); - } - if (!_precondhandler.TryAdd(id, new())) - { - throw new PipeAndFilterException( - PipeAndFilterException.StatusInit, - "idpipe already exists"); - } - if (!_tasks.TryAdd(id, new())) - { - throw new PipeAndFilterException( - PipeAndFilterException.StatusInit, - "idpipe already exists"); - } + _pipes.Add(new PipeCommand(id, agregatetask, command)); + _currentPipe = id; + _currentTask = null; + } private void SharedWithCondition(Func, CancellationToken, ValueTask> condition, string? aliasgoto, string? namecondition) @@ -339,19 +325,11 @@ private void SharedWithCondition(Func, CancellationToken, ValueTask { namecondition = condition.Method.Name; } - if (_precondhandler.TryGetValue(_currentPipe!, out var precod)) - { - precod.Add(new PipeCondition(condition, aliasgoto, namecondition)); - } - else - { - throw new PipeAndFilterException( - PipeAndFilterException.StatusInit, - "Current Pipe not found"); - } + var index = _pipes.FindIndex(x => x.Id == _currentPipe!); + _pipes[index].Condtitions.Add(new PreCondition(condition, aliasgoto, namecondition)); } - private void SharedAddTask(Func, CancellationToken, Task> command, Func, CancellationToken, ValueTask>? condition, string? nametask, string? namecond) + private void SharedAddTask(Func, CancellationToken, Task> command, string? nametask) { var id = Guid.NewGuid().ToString(); if (string.IsNullOrEmpty(_currentPipe)) @@ -360,41 +338,19 @@ private void SharedAddTask(Func, CancellationToken, Task> command, PipeAndFilterException.StatusInit, "Pipe not exist to add task"); } - if (!_aggregateTasks.TryGetValue(_currentPipe!, out _)) - { - throw new PipeAndFilterException( - PipeAndFilterException.StatusInit, - "Pipe not aggregate tasks"); - } if (command == null) { throw new PipeAndFilterException( PipeAndFilterException.StatusInit, "command cannot be null"); } - if (_tasks.TryGetValue(_currentPipe!, out var tasks)) + _currentTask = id; + if (string.IsNullOrEmpty(nametask)) { - if (condition != null && string.IsNullOrEmpty(namecond)) - { - namecond = condition.Method.Name; - } - if (string.IsNullOrEmpty(nametask)) - { - nametask = command.Method.Name; - } - PipeCondition? pipecond = null; - if (condition != null) - { - pipecond = new PipeCondition(condition, null, nametask); - } - tasks.Add(new PipeTask(id, command, pipecond, nametask, namecond)); - } - else - { - throw new PipeAndFilterException( - PipeAndFilterException.StatusInit, - "Pipe not found to add task"); + nametask = command.Method.Name; } + var index = _pipes.FindIndex(x => x.Id == _currentPipe! && x.IsAgregate); + _pipes[index].Tasks.Add(new PipeTask(_currentTask, command, nametask)); } } diff --git a/Src/Control/internal/PipeAndFilterControl.cs b/Src/Control/internal/PipeAndFilterControl.cs index 1de2e7d..2948d6a 100644 --- a/Src/Control/internal/PipeAndFilterControl.cs +++ b/Src/Control/internal/PipeAndFilterControl.cs @@ -3,6 +3,7 @@ // The maintenance and evolution is maintained by the PipeAndFilter project under MIT license // ******************************************************************************************** +using System; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.Extensions.Logging; @@ -16,8 +17,8 @@ internal class PipeAndFilterControl : IDisposable,IPipeAndFilterInit where private readonly List _tasks = new(); private readonly object _lockObj = new(); private readonly List _sequencePipes = new(); - private readonly List<(string? Alias, string Id, string? Value)> _savedvalues = new(); - private readonly List<(string? Alias, string Id, string? Value)> _savedtaskvalues = new(); + private readonly Dictionary _savedvalues = new(); + private readonly List<(string id, string? value, bool toremove)> _savedtaskvalues = new(); private readonly Dictionary> _status = new(); private bool _disposed; @@ -126,10 +127,32 @@ private async ValueTask> ExecutePipes() var sta = HandlerStatus.Created; try { - _savedtaskvalues.Clear(); - if (_parameters.AggregateTasks[_currentPipe!]) + if (_parameters.Pipes[_currentPipeIndex].IsAgregate) { - await ExecuteTasksPipes(_parameters.Tasks[_currentPipe!]); + _savedtaskvalues.Clear(); + await ExecuteTasksPipes(_parameters.Pipes[_currentPipeIndex].Tasks, _parameters.Pipes[_currentPipeIndex].MaxDegreeProcess); + if (!IsEnd) + { + foreach(var (id, value, toremove) in _savedtaskvalues) + { + if (toremove) + { + _savedvalues.Remove(id); + } + else + { + if (_savedvalues.ContainsKey(id)) + { + _savedvalues[id] = value; + } + else + { + _savedvalues.Add(id,value); + } + } + } + } + _savedtaskvalues.Clear(); } if (!IsEnd) { @@ -143,15 +166,14 @@ private async ValueTask> ExecutePipes() _cid, _logger, ChangeContract!, - _savedvalues.ToImmutableArray(), - _savedtaskvalues.ToImmutableArray(), + _savedvalues.ToImmutableDictionary(), _prevPipe, _currentPipe!, aliasprev, aliascur); - await _parameters.Pipes.First(x => x.Id == _currentPipe!).Handler(evt, _pipects!.Token); + await _parameters.Pipes[_currentPipeIndex].Handler(evt, _pipects!.Token); sta = HandlerStatus.Completed; elapsed = tm.Elapsed; - EnsureResultEventPipe(_currentPipe!, evt); + EnsureResultEventPipe(evt); } } catch (OperationCanceledException) @@ -220,7 +242,7 @@ private async Task NextPipe() while (!IsEnd) { var isok = true; - foreach (var itemcond in _parameters.PreConditions[_currentPipe!]) + foreach (var itemcond in _parameters.Pipes[_currentPipeIndex].Condtitions) { var condpipeType = string.IsNullOrEmpty(itemcond.GotoId) ? HandlerType.Condition : HandlerType.ConditionGoto; var sta = HandlerStatus.Created; @@ -235,8 +257,7 @@ private async Task NextPipe() _cid, _logger, ChangeContract!, - _savedvalues.ToImmutableArray(), - _savedtaskvalues.ToImmutableArray(), + _savedvalues.ToImmutableDictionary(), _prevPipe, _currentPipe!, aliasprev, aliascur); @@ -248,7 +269,7 @@ private async Task NextPipe() isok = await itemcond.Handle!(evt, _pipects!.Token); elapsed = tm.Elapsed; sta = HandlerStatus.Completed; - EnsureResultEventPipe(_currentPipe!, evt); + EnsureResultEventPipe(evt); } catch (OperationCanceledException) { @@ -313,31 +334,28 @@ private async Task NextPipe() } } - private void EnsureResultEventPipe(string idpipe, EventPipe eventPipe) + private void EnsureResultEventPipe(EventPipe eventPipe) { if (eventPipe.FinishedPipeAndFilter) { _finished = true; } - var alias = _parameters.IdToAlias[idpipe]; - if (eventPipe.ToRemove) - { - var index = _savedvalues.FindIndex(x => x.Id == idpipe); - if (index >= 0) - { - _savedvalues.RemoveAt(index); - } - } - else if (eventPipe.IsSaved) + foreach (var (id, value, toremove) in eventPipe.ToSaveRemove) { - var index = _savedvalues.FindIndex(x => x.Id == idpipe); - if (index >= 0) + if (toremove) { - _savedvalues[index] = (alias, idpipe, eventPipe.ValueToSave); + _savedvalues.Remove(id); } else { - _savedvalues.Add((alias, idpipe, eventPipe.ValueToSave)); + if (_savedvalues.ContainsKey(id)) + { + _savedvalues[id] = value; + } + else + { + _savedvalues.Add(id, value); + } } } } @@ -354,19 +372,17 @@ private void ChangeContract(Action eventchange) } } - private async Task ExecuteTasksPipes(IImmutableList> tasks) + private async Task ExecuteTasksPipes(List> tasks,int maxDegreeProcess) { var i = 0; - var maxDegreeProcess = _parameters.MaxDegreeProcess[_currentPipe!]; _savedtaskvalues.Clear(); - var emptytask = _savedtaskvalues.ToImmutableArray(); do { var degreecount = 0; do { var isvalidtask = true; - if (tasks[i].Condition.HasValue) + foreach (var item in tasks[i].Condtitions) { HandlerStatus sta; string? aliasprev = null; @@ -380,8 +396,7 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) _cid, _logger, ChangeContract!, - _savedvalues.ToImmutableArray(), - emptytask, + _savedvalues.ToImmutableDictionary(), _prevPipe, _currentPipe!, aliasprev, aliascur); @@ -390,10 +405,10 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) var tm = Stopwatch.StartNew(); try { - isvalidtask = await tasks[i].Condition!.Value.Handle!(evt, _pipects!.Token); + isvalidtask = await item.Handle!(evt, _pipects!.Token); elapsed = tm.Elapsed; sta = HandlerStatus.Completed; - EnsureResultEventPipeTask(tasks[i].Id, tasks[i].NameTask, evt); + EnsureResultEventPipe(evt); } catch (OperationCanceledException) { @@ -410,7 +425,7 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) HandlerType.ConditionTask, sta, elapsed, - tasks[i].NameTask, + tasks[i].Name, null, isvalidtask), "Error handler Condition Task", ex); @@ -423,13 +438,18 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) HandlerType.ConditionTask, sta, elapsed, - tasks[i].NameTask, + item.Name, null, isvalidtask)); if (IsEnd) { isvalidtask = false; } + if (!isvalidtask) + { + break; + } } + if (isvalidtask) { _tasks.Add(new Task((param) => @@ -438,14 +458,12 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) string? aliascur = null; EventPipe evt; Func, CancellationToken, Task> handle; - string taskid; string? taskname; lock (_lockObj) { var index = (int)param!; handle = tasks[index].Handler; - taskid = tasks[index].Id; - taskname = tasks[index].NameTask; + taskname = tasks[index].Name; if (!string.IsNullOrEmpty(_prevPipe)) { aliasprev = _parameters.IdToAlias[_prevPipe]; @@ -455,8 +473,7 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) _cid, _logger, ChangeContract!, - _savedvalues.ToImmutableArray(), - _savedtaskvalues.ToImmutableArray(), + _savedvalues.ToImmutableDictionary(), _prevPipe, _currentPipe!, aliasprev, aliascur); @@ -469,13 +486,12 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) handle(evt, _pipects!.Token).Wait(_pipects.Token); elapsed = tm.Elapsed; sta = HandlerStatus.Completed; - EnsureResultEventPipeTask(taskid, taskname, evt); + EnsureResultEventPipeTask(evt); } catch (OperationCanceledException) { elapsed = tm.Elapsed; sta = HandlerStatus.Canceled; - EnsureResultEventPipeTask(taskid, taskname, evt); lock (_lockObj) { _finished = true; @@ -485,7 +501,6 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) { elapsed = tm.Elapsed; sta = HandlerStatus.Faulted; - EnsureResultEventPipeTask(taskid, taskname, evt); lock (_lockObj) { _lastexception = new PipeAndFilterException( @@ -541,7 +556,7 @@ private async Task ExecuteTasksPipes(IImmutableList> tasks) } while (!IsEnd && i < tasks.Count); } - private void EnsureResultEventPipeTask(string idtask, string? name, EventPipe eventPipe) + private void EnsureResultEventPipeTask(EventPipe eventPipe) { lock (_lockObj) { @@ -549,29 +564,8 @@ private void EnsureResultEventPipeTask(string idtask, string? name, EventPipe { _finished = true; } - if (eventPipe.ToRemove) - { - var index = _savedtaskvalues.FindIndex(x => x.Id == idtask); - if (index >= 0) - { - _savedtaskvalues.RemoveAt(index); - } - } - else if (eventPipe.IsSaved) - { - var index = _savedvalues.FindIndex(x => x.Id == idtask); - if (index >= 0) - { - _savedtaskvalues[index] = (name, idtask, eventPipe.ValueToSave); - } - else - { - _savedtaskvalues.Add((name, idtask, eventPipe.ValueToSave)); - } - } + _savedtaskvalues.AddRange(eventPipe.ToSaveRemove); } } - - } } diff --git a/Src/Control/internal/PipeAndFilterService.cs b/Src/Control/internal/PipeAndFilterService.cs index 95c29ef..3c35446 100644 --- a/Src/Control/internal/PipeAndFilterService.cs +++ b/Src/Control/internal/PipeAndFilterService.cs @@ -17,19 +17,12 @@ public PipeAndFilterService(string? serviceid, IPipeAndFilterOptions paramete public string? ServiceId => _serviceid; - public IImmutableDictionary AliasToId => _parameters.AliasToId; + public ImmutableDictionary AliasToId => _parameters.AliasToId; - public IImmutableDictionary IdToAlias => _parameters.IdToAlias; + public ImmutableDictionary IdToAlias => _parameters.IdToAlias; - public IImmutableDictionary MaxDegreeProcess => _parameters.MaxDegreeProcess; + public ImmutableList> Pipes => _parameters.Pipes; - public IImmutableList> Pipes => _parameters.Pipes; - - public IImmutableDictionary AggregateTasks => _parameters.AggregateTasks; - - public IImmutableDictionary>> PreConditions => _parameters.PreConditions; - - public IImmutableDictionary>> Tasks => _parameters.Tasks; #endregion diff --git a/Src/Control/internal/PipeCommand.cs b/Src/Control/internal/PipeCommand.cs index b52c052..554e572 100644 --- a/Src/Control/internal/PipeCommand.cs +++ b/Src/Control/internal/PipeCommand.cs @@ -1,13 +1,21 @@ namespace PipeFilterCore { - internal readonly struct PipeCommand where T : class + internal class PipeCommand where T : class { - public PipeCommand(string id, Func, CancellationToken, Task> handler) + public PipeCommand(string id,bool isagregate, Func, CancellationToken, Task> handler) { Id = id; + IsAgregate = isagregate; + MaxDegreeProcess = Environment.ProcessorCount; Handler = handler; + Tasks = new(); + Condtitions = new(); } public string Id { get; } + public bool IsAgregate { get; } + public int MaxDegreeProcess { get; set; } + public List> Tasks { get; } + public List> Condtitions { get; } public Func, CancellationToken, Task> Handler { get; } } } diff --git a/Src/Control/internal/PipeTask.cs b/Src/Control/internal/PipeTask.cs index 4d89d2a..83f2497 100644 --- a/Src/Control/internal/PipeTask.cs +++ b/Src/Control/internal/PipeTask.cs @@ -14,18 +14,16 @@ public PipeTask() "Invalid ctor PipeTask"); } - public PipeTask(string id, Func, CancellationToken, Task> handler, PipeCondition? condition, string? nameTask, string? nameCondition) + public PipeTask(string id, Func, CancellationToken, Task> handler, string? nameTask) { Id = id; Handler = handler; - Condition = condition; - NameTask = nameTask; - NameCondition = nameCondition; + Name = nameTask; + Condtitions = new(); } public string Id { get; } public Func, CancellationToken, Task> Handler { get; } - public PipeCondition? Condition { get; } - public string? NameTask { get; } - public string? NameCondition { get; } + public List> Condtitions { get; } + public string? Name { get; } } } diff --git a/Src/Control/internal/PipeCondition.cs b/Src/Control/internal/PreCondition.cs similarity index 78% rename from Src/Control/internal/PipeCondition.cs rename to Src/Control/internal/PreCondition.cs index 58923d0..cd79b19 100644 --- a/Src/Control/internal/PipeCondition.cs +++ b/Src/Control/internal/PreCondition.cs @@ -5,16 +5,16 @@ namespace PipeFilterCore { - internal readonly struct PipeCondition where T : class + internal readonly struct PreCondition where T : class { - public PipeCondition() + public PreCondition() { throw new PipeAndFilterException( PipeAndFilterException.StatusInit, "Invalid ctor PipeCondition"); } - public PipeCondition(Func, CancellationToken, ValueTask>? handle, string? gotoId, string? name) + public PreCondition(Func, CancellationToken, ValueTask>? handle, string? gotoId, string? name) { Handle = handle; GotoId = gotoId; diff --git a/Src/NugetREADME.md b/Src/NugetREADME.md index 3d7f290..293091e 100644 --- a/Src/NugetREADME.md +++ b/Src/NugetREADME.md @@ -4,47 +4,62 @@ **PipeAndFilter** was developed in C# with the **netstandard2.1**, **.NET 6** and **.NET 7** target frameworks. -## What's new in V1.0.1 - -- First Release G.A +## What's new in V1.0.2 + +- Added ability to save/overwrite multiple result to use during the execution another pipe / aggregation pipe + - Removed propery 'SavedTasks' in EventPipe + - Removed propery 'SavedPipes' in EventPipe + - Removed Method 'SaveValue' + - Removed Method 'RemoveSavedValue' + - Added Method TrySavedValue + - Now TrySavedValue return true/false if exist id saved and value in out paramameter + - Added Method SaveValueAtEnd + - Now SaveValueAtEnd receives the unique id to be saved/overwrite and the value + - Added Method RemoveValueAtEnd + - Now RemoveValueAtEnd receives the unique id to be removed if any +- Added ability to multiple preconditions for Tasks + - Channged command AddTaskCondition + - Now the same parameters as AddTask + - Added command WithCondition for AddTaskCondition ## Features -[**Top**](#table-of-contents) -- Contract with thread safety for change values +- Thread safety to obtain/change contract values ​​and/or generic purpose when running a Task (pararel execute) +- Add multiple pipe +- Add multiple agregate pipe (for run pararel tasks) - Set the maximum amount of parallel execution -- Add multiple preconditions to run a pipe +- Add multiple preconditions to run a pipe or task - Add multiple link to the pipe to jump to another pipe -- Add tasks with a precondition - Have detailed status (execution date, execution time, type of execution, result of each execution) and number of executions in each pipe -- Save a result from each pipe to use when executing another pipe -- Save a result from each task to use during the execution of the aggregation pipe +- Save multiple results from each pipe to be used during the another pipe/aggregate pipe run +- Save multiple results in each task to be effective during the aggregation pipe run - Terminate the PipeAndFilter on any task, condition or pipe - Simple and clear fluent syntax ## Usage -[**Top**](#table-of-contents) The **PipeAndFilter** use **fluent interface**; an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility. The term was coined in 2005 by Eric Evans and Martin Fowler. ### Sample-Console Usage ```csharp -var result = await PipeAndFilter.New() - .AddPipe(ExecPipe1) - .WithGotoCondition(CondFalse, "LastPipe") - .WithCondition(CondTrue) - .WithCondition(CondTrue) - .AddPipe(ExecPipe2) - .AddPipe(ExecPipe3) - .AddPipeTasks(AgregateTask) - .WithCondition(CondTrue) +await PipeAndFilter.New() + .AddPipe(Pipe1) + .WithGotoCondition(Cond0, "LastPipe") + .WithCondition(Cond1) + .WithCondition(Cond2) + .AddPipe(Pipe2) + .AddPipe(Pipe3) + .AddPipeTasks(Pipe4) + .WithCondition(Cond1) .MaxDegreeProcess(4) - .AddTask(Task1) - .AddTaskCondition(Task2, CondFalse) - .AddTask(Task3) - .AddPipe(ExecPipe5, "LastPipe") + .AddTask(Task50) + .AddTaskCondition(Task100) + .WithCondition(Cond3) + .WithCondition(Cond4) + .AddTask(Task150) + .AddPipe(Pipe5, "LastPipe") .BuildAndCreate() .Init(contract) .CorrelationId(null) @@ -53,19 +68,18 @@ var result = await PipeAndFilter.New() ``` ### Sample-api/webUsage -[**Top**](#table-of-contents) ```csharp builder.Services .AddPipeAndFilter( PipeAndFilter.New() - .AddPipe(ExecPipe) + .AddPipe(TemperatureAdd10) .Build()); ``` ```csharp -private static Task ExecPipe(EventPipe pipe, CancellationToken token) +private static Task TemperatureAdd10(EventPipe pipe, CancellationToken token) { pipe.ThreadSafeAccess((contract) => { @@ -81,9 +95,9 @@ private static Task ExecPipe(EventPipe pipe, CancellationToken public class WeatherForecastController : ControllerBase { private readonly ILogger _logger; - private readonly IPipeAndFilterServiceBuild _mypipe; + private readonly IPipeAndFilterService _mypipe; - public WeatherForecastController(ILogger logger, IPipeAndFilterServiceBuild pipeAndFilter) + public WeatherForecastController(ILogger logger, IPipeAndFilterService pipeAndFilter) { _logger = logger; _mypipes = pipeAndFilter; diff --git a/Src/PipeAndFilter.csproj b/Src/PipeAndFilter.csproj index 7f03cac..15c49e2 100644 --- a/Src/PipeAndFilter.csproj +++ b/Src/PipeAndFilter.csproj @@ -20,13 +20,13 @@ PipeAndFilter component for .NET Core with flexible conditions for each step (pipe) and the ability to parallel execute tasks over a pipe. https://github.com/FRACerqueira/PipeAndFilter/releases - csharp;dotnet;Pipeline;Pipe;PipeAndFilter + csharp;dotnet;pipeline;pipe;pipefilter;workflow https://github.com/FRACerqueira/PipeAndFilter git PipeAndFilter NugetREADME.md https://fracerqueira.github.io/PipeAndFilter - 1.0.0 + 1.0.2 icon.png © 2023 - Fernando Cerqueira False diff --git a/Src/README.txt b/Src/README.txt index d9465cd..dbf9747 100644 --- a/Src/README.txt +++ b/Src/README.txt @@ -16,14 +16,15 @@ and the ability to parallel execute tasks over a pipe. Key features ------------ -- Contract with thread safety for change values +- Thread safety to obtain/change contract values ​​and/or generic purpose when running a Task (pararel execute) +- Add multiple pipe +- Add multiple agregate pipe (for run pararel tasks) - Set the maximum amount of parallel execution -- Add multiple preconditions to run a pipe +- Add multiple preconditions to run a pipe or task - Add multiple link to the pipe to jump to another pipe -- Add tasks with a precondition - Have detailed status (execution date, execution time, type of execution, result of each execution) and number of executions in each pipe -- Save a result from each pipe to use when executing another pipe -- Save a result from each task to use during the execution of the aggregation pipe +- Save multiple results from each pipe to be used during the another pipe/aggregate pipe run +- Save multiple results in each task to be effective during the aggregation pipe run - Terminate the PipeAndFilter on any task, condition or pipe - Simple and clear fluent syntax @@ -36,27 +37,43 @@ PipeAndFilter was developed in C# with target frameworks: - .NET 6 - .NET 7 -*** What's new in V1.0.1 *** +*** What's new in V1.0.2 *** ---------------------------- -- First Release G.A +- Added ability to save/overwrite multiple result to use during the execution another pipe / aggregation pipe + - Removed propery 'SavedTasks' in EventPipe + - Removed propery 'SavedPipes' in EventPipe + - Removed Method 'SaveValue' + - Removed Method 'RemoveSavedValue' + - Added Method TrySavedValue + - Now TrySavedValue return true/false if exist id saved and value in out paramameter + - Added Method SaveValueAtEnd + - Now SaveValueAtEnd receives the unique id to be saved/overwrite and the value + - Added Method RemoveValueAtEnd + - Now RemoveValueAtEnd receives the unique id to be removed if any +- Added ability to multiple preconditions for Tasks + - Channged command AddTaskCondition + - Now the same parameters as AddTask + - Added command WithCondition for AddTaskCondition **PipeAndFilter Sample-console Usage** -------------------------------------- -var result = await PipeAndFilter.New() - .AddPipe(ExecPipe1) - .WithGotoCondition(CondFalse, "LastPipe") - .WithCondition(CondTrue) - .WithCondition(CondTrue) - .AddPipe(ExecPipe2) - .AddPipe(ExecPipe3) - .AddPipeTasks(AgregateTask) - .WithCondition(CondTrue) +await PipeAndFilter.New() + .AddPipe(Pipe1) + .WithGotoCondition(Cond0, "LastPipe") + .WithCondition(Cond1) + .WithCondition(Cond2) + .AddPipe(Pipe2) + .AddPipe(Pipe3) + .AddPipeTasks(Pipe4) + .WithCondition(Cond1) .MaxDegreeProcess(4) - .AddTask(Task1) - .AddTaskCondition(Task2, CondFalse) - .AddTask(Task3) - .AddPipe(ExecPipe5, "LastPipe") + .AddTask(Task50) + .AddTaskCondition(Task100) + .WithCondition(Cond3) + .WithCondition(Cond4) + .AddTask(Task150) + .AddPipe(Pipe5, "LastPipe") .BuildAndCreate() .Init(contract) .CorrelationId(null) @@ -71,11 +88,11 @@ Program.cs builder.Services .AddPipeAndFilter(PipeAndFilter.New() - .AddPipe(ExecPipe) + .AddPipe(TemperatureAdd10) .Build()); ... -private static Task ExecPipe(EventPipe pipe, CancellationToken token) +private static Task TemperatureAdd10(EventPipe pipe, CancellationToken token) { pipe.ThreadSafeAccess((contract) => { @@ -93,9 +110,9 @@ WeatherForecastController.cs public class WeatherForecastController : ControllerBase { private readonly ILogger _logger; - private readonly IPipeAndFilterServiceBuild _mypipe; + private readonly IPipeAndFilterService _mypipe; - public WeatherForecastController(ILogger logger, IPipeAndFilterServiceBuild pipeAndFilter) + public WeatherForecastController(ILogger logger, IPipeAndFilterService pipeAndFilter) { _logger = logger; _mypipes = pipeAndFilter; diff --git a/docs/apis/apis.md b/docs/apis/apis.md index a30a7f6..fedd992 100644 --- a/docs/apis/apis.md +++ b/docs/apis/apis.md @@ -31,6 +31,8 @@ - [IPipeAndFilterStart<T>](./pipefiltercore.ipipeandfilterstart-1.md) +- [IPipeAndFilterTaskCondition<T>](./pipefiltercore.ipipeandfiltertaskcondition-1.md) + - [IPipeAndFilterTasks<T>](./pipefiltercore.ipipeandfiltertasks-1.md) - [PipeAndFilter](./pipefiltercore.pipeandfilter.md) diff --git a/docs/apis/pipefiltercore.eventpipe-1.md b/docs/apis/pipefiltercore.eventpipe-1.md index ed9eff1..10b74e6 100644 --- a/docs/apis/pipefiltercore.eventpipe-1.md +++ b/docs/apis/pipefiltercore.eventpipe-1.md @@ -74,40 +74,14 @@ public ILogger Logger { get; } ILogger
-### **SavedPipes** - -The values saved ​​associated with pipes. -
The values ​​are serialized in json.
Null result may exist. - -```csharp -public ImmutableArray> SavedPipes { get; } -``` - -#### Property Value - -ImmutableArray<ValueTuple<String, String, String>>
- -###
**SavedTasks** - -The values saved ​​associated with tasks. -
Data only exists when executed by an aggregator pipe.
The values ​​are serialized in json.
Null result may exist. - -```csharp -public ImmutableArray> SavedTasks { get; } -``` - -#### Property Value - -ImmutableArray<ValueTuple<String, String, String>>
- ## Constructors -###
**EventPipe(String, ILogger, Action<Action<T>>, ImmutableArray<ValueTuple<String, String, String>>, ImmutableArray<ValueTuple<String, String, String>>, String, String, String, String)** +### **EventPipe(String, ILogger, Action<Action<T>>, ImmutableDictionary<String, String>, String, String, String, String)** Create instance of Event-Pipe (Only internal use or Unit-Test). ```csharp -public EventPipe(string cid, ILogger logger, Action> changecontract, ImmutableArray> savedpipes, ImmutableArray> savedtasks, string fromId, string currentId, string fromAlias, string currentAlias) +public EventPipe(string cid, ILogger logger, Action> changecontract, ImmutableDictionary savedvalues, string fromId, string currentId, string fromAlias, string currentAlias) ``` #### Parameters @@ -121,11 +95,8 @@ Handle of log. `changecontract` Action<Action<T>>
Handle of changecontract. -`savedpipes` ImmutableArray<ValueTuple<String, String, String>>
-The values saved by pipe. - -`savedtasks` ImmutableArray<ValueTuple<String, String, String>>
-The values saved by tasks. +`savedvalues` ImmutableDictionary<String, String>
+The values saved. `fromId` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
The previous Id. @@ -149,21 +120,27 @@ End PipeAndFilter. public void EndPipeAndFilter() ``` -###
**RemoveSavedValue()** +### **RemoValueAtEnd(String)** -Remove a value associated with this pipe or task. +Remove a value associated with a unique key at the end of this event (If this event is not a task event). +
Values ​​removed in the task event will only take effect in the pipe aggregation event
A task event cannot see values ​​saved and/or removed by another task.
In a task event, Never try to overwrite a value already saved by another event, the results may not be as expected as the execution sequence is not guaranteed. ```csharp -public void RemoveSavedValue() +public void RemoValueAtEnd(string id) ``` -###
**SaveValue<T1>(T1)** +#### Parameters + +`id` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The unique key Id. -Save/overwrite a value associated with this pipe or task. -
The values ​​will serialize into json. +###
**SaveValueAtEnd<T1>(String, T1)** + +Save/replace a value associated with a unique key at the end of this event(If this event is not a task event). +
Values ​​saved in the task event will only take effect in the pipe aggregation event
A task event cannot see values ​​saved and/or removed by another task.
In a task event, Never try to overwrite a value already saved by another event, the results may not be as expected as the execution sequence is not guaranteed.
The values ​​will serialize into json. ```csharp -public void SaveValue(T1 value) +public void SaveValueAtEnd(string id, T1 value) ``` #### Type Parameters @@ -173,6 +150,9 @@ Type value to save. #### Parameters +`id` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The unique key Id. + `value` T1
The value to save. @@ -191,6 +171,27 @@ public void ThreadSafeAccess(Action action) The action to access.
The action will only be executed if the contract exists(not null). +###
**TrySavedValue(String, ref String)** + +Try get value saved ​​associated with a unique key. +
The values ​​are serialized in json.
Null result may exist. + +```csharp +public bool TrySavedValue(string id, ref String value) +``` + +#### Parameters + +`id` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The unique key Id. + +`value` [String&](https://docs.microsoft.com/en-us/dotnet/api/system.string&)
+The value saved if any. + +#### Returns + +True if value exists, otherwise false with null value + - - - [**Back to List Api**](./apis.md) diff --git a/docs/apis/pipefiltercore.ipipeandfiltercreate-1.md b/docs/apis/pipefiltercore.ipipeandfiltercreate-1.md deleted file mode 100644 index c45d04c..0000000 --- a/docs/apis/pipefiltercore.ipipeandfiltercreate-1.md +++ /dev/null @@ -1,55 +0,0 @@ -# PipeAndFilter API:IPipeAndFilterCreate - -[![Build](https://github.com/FRACerqueira/PipeAndFilter/workflows/Build/badge.svg)](https://github.com/FRACerqueira/PipeAndFilter/actions/workflows/build.yml) -[![License](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/FRACerqueira/PipeAndFilter/blob/master/LICENSE) -[![NuGet](https://img.shields.io/nuget/v/PipeAndFilter)](https://www.nuget.org/packages/PipeAndFilter/) -[![Downloads](https://img.shields.io/nuget/dt/PipeAndFilter)](https://www.nuget.org/packages/PipeAndFilter/) - -[**Back to List Api**](./apis.md) - -# IPipeAndFilterCreate<T> - -Namespace: PipeFilterCore - -Represents the commands for create a instance. - -```csharp -public interface IPipeAndFilterCreate -``` - -#### Type Parameters - -`T`
-Type of contract. - -## Properties - -###
**ServiceId** - -The service id for this type. - -```csharp -public abstract string ServiceId { get; } -``` - -#### Property Value - -[String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
- -## Methods - -###
**Create()** - -Create a instance. - -```csharp -IPipeAndFilterInit Create() -``` - -#### Returns - -[IPipeAndFilterInit<T>](./pipefiltercore.ipipeandfilterinit-1.md) - - -- - - -[**Back to List Api**](./apis.md) diff --git a/docs/apis/pipefiltercore.ipipeandfiltertaskcondition-1.md b/docs/apis/pipefiltercore.ipipeandfiltertaskcondition-1.md new file mode 100644 index 0000000..7d73399 --- /dev/null +++ b/docs/apis/pipefiltercore.ipipeandfiltertaskcondition-1.md @@ -0,0 +1,114 @@ +# PipeAndFilter API:IPipeAndFilterTaskCondition + +[![Build](https://github.com/FRACerqueira/PipeAndFilter/workflows/Build/badge.svg)](https://github.com/FRACerqueira/PipeAndFilter/actions/workflows/build.yml) +[![License](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/FRACerqueira/PipeAndFilter/blob/master/LICENSE) +[![NuGet](https://img.shields.io/nuget/v/PipeAndFilter)](https://www.nuget.org/packages/PipeAndFilter/) +[![Downloads](https://img.shields.io/nuget/dt/PipeAndFilter)](https://www.nuget.org/packages/PipeAndFilter/) + +[**Back to List Api**](./apis.md) + +# IPipeAndFilterTaskCondition<T> + +Namespace: PipeFilterCore + +Represents commands for conditions. + +```csharp +public interface IPipeAndFilterTaskCondition : IPipeAndFilterBuild +``` + +#### Type Parameters + +`T`
+Type of contract. + +Implements IPipeAndFilterBuild<T> + +## Methods + +###
**AddPipe(Func<EventPipe<T>, CancellationToken, Task>, String)** + +Add new pipe. + +```csharp +IPipeAndFilterAdd AddPipe(Func, CancellationToken, Task> command, string alias) +``` + +#### Parameters + +`command` Func<EventPipe<T>, CancellationToken, Task>
+The handler pipe to execute. + +`alias` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The unique alias for pipe. +
If the alias is omitted, the alias will be the handler name followed by the reference quantity (if any).
Alias ​​is used to reference in another pipe. + +#### Returns + +[IPipeAndFilterAdd<T>](./pipefiltercore.ipipeandfilteradd-1.md) + +###
**AddPipeTasks(Func<EventPipe<T>, CancellationToken, Task>, String)** + +Add new pipe aggregate tasks. + +```csharp +IPipeAndFilterTasks AddPipeTasks(Func, CancellationToken, Task> command, string alias) +``` + +#### Parameters + +`command` Func<EventPipe<T>, CancellationToken, Task>
+The handler pipe aggregate to execute. +
The handler command will run after all tasks are executed. + +`alias` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The unique alias for pipe. +
If the alias is omitted, the alias will be the handler name followed by the reference quantity (if any).
Alias ​​is used to reference in another pipe. + +#### Returns + +[IPipeAndFilterTasks<T>](./pipefiltercore.ipipeandfiltertasks-1.md) + +###
**AddTask(Func<EventPipe<T>, CancellationToken, Task>, String)** + +Add new task (execution in parallel) through pipe. + +```csharp +IPipeAndFilterTasks AddTask(Func, CancellationToken, Task> command, string nametask) +``` + +#### Parameters + +`command` Func<EventPipe<T>, CancellationToken, Task>
+The handler task to execute. + +`nametask` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The name for task (optional). + +#### Returns + +[IPipeAndFilterTasks<T>](./pipefiltercore.ipipeandfiltertasks-1.md) + +###
**WithCondition(Func<EventPipe<T>, CancellationToken, ValueTask<Boolean>>, String)** + +Add new condition for task. + +```csharp +IPipeAndFilterTaskCondition WithCondition(Func, CancellationToken, ValueTask> condition, string namecondition) +``` + +#### Parameters + +`condition` Func<EventPipe<T>, CancellationToken, ValueTask<Boolean>>
+The handle condition to execute. + +`namecondition` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
+The name for condition(optional). + +#### Returns + +[IPipeAndFilterTaskCondition<T>](./pipefiltercore.ipipeandfiltertaskcondition-1.md) + + +- - - +[**Back to List Api**](./apis.md) diff --git a/docs/apis/pipefiltercore.ipipeandfiltertasks-1.md b/docs/apis/pipefiltercore.ipipeandfiltertasks-1.md index d45e2a3..df274f6 100644 --- a/docs/apis/pipefiltercore.ipipeandfiltertasks-1.md +++ b/docs/apis/pipefiltercore.ipipeandfiltertasks-1.md @@ -89,12 +89,12 @@ The name for task (optional). [IPipeAndFilterTasks<T>](./pipefiltercore.ipipeandfiltertasks-1.md) -###
**AddTaskCondition(Func<EventPipe<T>, CancellationToken, Task>, Func<EventPipe<T>, CancellationToken, ValueTask<Boolean>>, String, String)** +### **AddTaskCondition(Func<EventPipe<T>, CancellationToken, Task>, String)** -Add new task (execution in parallel) through pipe with a condition. +Add new task (execution in parallel) through pipe with conditions. ```csharp -IPipeAndFilterTasks AddTaskCondition(Func, CancellationToken, Task> command, Func, CancellationToken, ValueTask> condition, string nametask, string namecondition) +IPipeAndFilterTaskCondition AddTaskCondition(Func, CancellationToken, Task> command, string nametask) ``` #### Parameters @@ -102,18 +102,12 @@ IPipeAndFilterTasks AddTaskCondition(Func, CancellationToken, Ta `command` Func<EventPipe<T>, CancellationToken, Task>
The handler task to execute. -`condition` Func<EventPipe<T>, CancellationToken, ValueTask<Boolean>>
-The handler task to condition. - `nametask` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
The name for task (optional). -`namecondition` [String](https://docs.microsoft.com/en-us/dotnet/api/system.string)
-The name for condition (optional). - #### Returns -[IPipeAndFilterTasks<T>](./pipefiltercore.ipipeandfiltertasks-1.md) +[IPipeAndFilterTaskCondition<T>](./pipefiltercore.ipipeandfiltertaskcondition-1.md) ###
**MaxDegreeProcess(Int32)** diff --git a/docs/images/PipeAndFilterFeature.png b/docs/images/PipeAndFilterFeature.png index e3d9b2d..c92aae0 100644 Binary files a/docs/images/PipeAndFilterFeature.png and b/docs/images/PipeAndFilterFeature.png differ diff --git a/docs/index.md b/docs/index.md index 13815dc..0be3e8c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,7 +15,7 @@ and the ability to parallel execute tasks over a pipe. ## Table of Contents -- [What's new - previous versions]() +- [What's new - previous versions](whatsnewprev.md) - [Features](#features) - [Installing](#installing) - [Examples](#examples) @@ -28,23 +28,38 @@ and the ability to parallel execute tasks over a pipe. - [API Reference](https://fracerqueira.github.io/PipeAndFilter/apis/apis.html) ## What's new in the latest version -### V1.0.1 +### V1.0.2 [**Top**](#table-of-contents) -- First Release G.A +- Added ability to save/overwrite multiple result to use during the execution another pipe / aggregation pipe + - Removed propery 'SavedTasks' in EventPipe + - Removed propery 'SavedPipes' in EventPipe + - Removed Method 'SaveValue' + - Removed Method 'RemoveSavedValue' + - Added Method TrySavedValue + - Now TrySavedValue return true/false if exist id saved and value in out paramameter + - Added Method SaveValueAtEnd + - Now SaveValueAtEnd receives the unique id to be saved/overwrite and the value + - Added Method RemoveValueAtEnd + - Now RemoveValueAtEnd receives the unique id to be removed if any +- Added ability to multiple preconditions for Tasks + - Channged command AddTaskCondition + - Now the same parameters as AddTask + - Added command WithCondition for AddTaskCondition ## Features [**Top**](#table-of-contents) -- Contract with thread safety for change values +- Thread safety to obtain/change contract values ​​and/or generic purpose when running a Task (pararel execute) +- Add multiple pipe +- Add multiple agregate pipe (for run pararel tasks) - Set the maximum amount of parallel execution -- Add multiple preconditions to run a pipe +- Add multiple preconditions to run a pipe or task - Add multiple link to the pipe to jump to another pipe -- Add tasks with a precondition - Have detailed status (execution date, execution time, type of execution, result of each execution) and number of executions in each pipe -- Save a result from each pipe to use when executing another pipe -- Save a result from each task to use during the execution of the aggregation pipe +- Save multiple results from each pipe to be used during the another pipe/aggregate pipe run +- Save multiple results in each task to be effective during the aggregation pipe run - Terminate the PipeAndFilter on any task, condition or pipe - Simple and clear fluent syntax @@ -78,20 +93,22 @@ The **PipeAndFilter** use **fluent interface**; an object-oriented API whose des ### Sample-Console Usage ```csharp -var result = await PipeAndFilter.New() - .AddPipe(ExecPipe1) - .WithGotoCondition(CondFalse, "LastPipe") - .WithCondition(CondTrue) - .WithCondition(CondTrue) - .AddPipe(ExecPipe2) - .AddPipe(ExecPipe3) - .AddPipeTasks(AgregateTask) - .WithCondition(CondTrue) +await PipeAndFilter.New() + .AddPipe(Pipe1) + .WithGotoCondition(Cond0, "LastPipe") + .WithCondition(Cond1) + .WithCondition(Cond2) + .AddPipe(Pipe2) + .AddPipe(Pipe3) + .AddPipeTasks(Pipe4) + .WithCondition(Cond1) .MaxDegreeProcess(4) - .AddTask(Task1) - .AddTaskCondition(Task2, CondFalse) - .AddTask(Task3) - .AddPipe(ExecPipe5, "LastPipe") + .AddTask(Task50) + .AddTaskCondition(Task100) + .WithCondition(Cond3) + .WithCondition(Cond4) + .AddTask(Task150) + .AddPipe(Pipe5, "LastPipe") .BuildAndCreate() .Init(contract) .CorrelationId(null) @@ -105,12 +122,12 @@ var result = await PipeAndFilter.New() ```csharp builder.Services .AddPipeAndFilter(PipeAndFilter.New() - .AddPipe(ExecPipe) + .AddPipe(TemperatureAdd10) .Build()); ``` ```csharp -private static Task ExecPipe(EventPipe pipe, CancellationToken token) +private static Task TemperatureAdd10(EventPipe pipe, CancellationToken token) { pipe.ThreadSafeAccess((contract) => { @@ -126,9 +143,9 @@ private static Task ExecPipe(EventPipe pipe, CancellationToken public class WeatherForecastController : ControllerBase { private readonly ILogger _logger; - private readonly IPipeAndFilterServiceBuild _mypipe; + private readonly IPipeAndFilterService _mypipe; - public WeatherForecastController(ILogger logger, IPipeAndFilterServiceBuild pipeAndFilter) + public WeatherForecastController(ILogger logger, IPipeAndFilterService pipeAndFilter) { _logger = logger; _mypipes = pipeAndFilter; @@ -158,65 +175,26 @@ All pipes, conditions and tasks do not perform any task, they are only called an See folder [**Samples/PipeandFIlterBenchmarking**](https://github.com/FRACerqueira/PipeAndFilter/tree/main/Samples/PipeandFIlterBenchmarking). ``` -BenchmarkDotNet v0.13.10, Windows 10 (10.0.19044.3570/21H2/November2021Update) -Intel Core i7-8565U CPU 1.80GHz (Whiskey Lake), 1 CPU, 8 logical and 4 physical cores -.NET SDK 8.0.100-rc.2.23502.2 - [Host] : .NET 8.0.0 (8.0.23.47906), X64 RyuJIT AVX2 - DefaultJob : .NET 8.0.0 (8.0.23.47906), X64 RyuJIT AVX2 -``` - -| Method | Mean | Error | StdDev | Median | Gen0 | Allocated | -|----------------------------- |-----------:|-----------:|-----------:|-----------:|--------:|----------:| -| PipeAsync | 7.419 us | 0.1483 us | 0.3347 us | 7.345 us | 1.1597 | 4.74 KB | -| PipeWith10Async | 239.257 us | 10.6802 us | 30.9852 us | 234.596 us | 19.5313 | 80.68 KB | -| PipeWithConditionAsync | 8.273 us | 0.1639 us | 0.2599 us | 8.146 us | 1.4038 | 5.76 KB | -| PipeWith10ConditionAsync | 20.606 us | 0.4113 us | 0.9774 us | 20.202 us | 3.6011 | 14.78 KB | -| PipeWith10ConditionGotoAsync | 33.396 us | 0.6631 us | 1.2455 us | 33.024 us | 5.1270 | 21.08 KB | -| PipeTaskAsync | 16.918 us | 0.5232 us | 1.5096 us | 16.795 us | 1.7090 | 7.07 KB | -| PipeWith10TaskAsync | 72.402 us | 3.5790 us | 9.8577 us | 68.424 us | 4.8828 | 20.47 KB | -| PipeTaskConditionAsync | 19.375 us | 0.3853 us | 0.9736 us | 19.425 us | 1.8616 | 7.66 KB | -| PipeWith10TaskConditionAsync | 63.898 us | 1.2774 us | 2.9858 us | 63.562 us | 4.8828 | 20.47 KB | - -``` +------------------------------------------------------------------------------------------------------ BenchmarkDotNet v0.13.10, Windows 10 (10.0.19044.3570/21H2/November2021Update) Intel Core i7-8565U CPU 1.80GHz (Whiskey Lake), 1 CPU, 8 logical and 4 physical cores .NET SDK 8.0.100-rc.2.23502.2 [Host] : .NET 7.0.13 (7.0.1323.51816), X64 RyuJIT AVX2 DefaultJob : .NET 7.0.13 (7.0.1323.51816), X64 RyuJIT AVX2 +------------------------------------------------------------------------------------------------------ +| Method | Mean | Error | StdDev | Median | Gen0 | Allocated | +|----------------------------- |----------:|----------:|----------:|----------:|--------:|----------:| +| PipeAsync | 3.990 us | 0.0460 us | 0.0384 us | 3.992 us | 0.8698 | 3.57 KB | +| PipeWith10Async | 97.574 us | 1.7283 us | 1.7748 us | 97.153 us | 15.0146 | 61.37 KB | +| PipeWithConditionAsync | 5.003 us | 0.0591 us | 0.0524 us | 5.003 us | 1.0834 | 4.45 KB | +| PipeWith10ConditionAsync | 13.157 us | 0.1262 us | 0.0985 us | 13.155 us | 3.1891 | 13.05 KB | +| PipeWith10ConditionGotoAsync | 18.253 us | 0.3007 us | 0.2347 us | 18.211 us | 3.9978 | 16.34 KB | +| PipeTaskAsync | 9.741 us | 0.1923 us | 0.3517 us | 9.649 us | 1.3275 | 5.45 KB | +| PipeWith10TaskAsync | 45.064 us | 0.7313 us | 0.8981 us | 44.984 us | 4.5166 | 18.58 KB | +| PipeTaskConditionAsync | 11.280 us | 0.1956 us | 0.1830 us | 11.312 us | 1.5564 | 6.39 KB | +| PipeWith10TaskConditionAsync | 48.034 us | 0.9578 us | 2.5895 us | 47.222 us | 4.5166 | 18.58 KB | ``` -| Method | Mean | Error | StdDev | Median | Gen0 | Allocated | -|----------------------------- |-----------:|----------:|-----------:|-----------:|--------:|----------:| -| PipeAsync | 11.231 μs | 0.4573 μs | 1.3195 μs | 10.898 μs | 1.1597 | 4.79 KB | -| PipeWith10Async | 226.285 μs | 4.5187 μs | 10.8264 μs | 222.330 μs | 19.5313 | 80.73 KB | -| PipeWithConditionAsync | 9.902 μs | 0.1137 μs | 0.0950 μs | 9.858 μs | 1.4038 | 5.8 KB | -| PipeWith10ConditionAsync | 26.949 μs | 0.9860 μs | 2.6824 μs | 26.154 μs | 3.6011 | 14.83 KB | -| PipeWith10ConditionGotoAsync | 39.820 μs | 0.7613 μs | 1.2075 μs | 39.498 μs | 5.1270 | 21.13 KB | -| PipeTaskAsync | 20.286 μs | 0.6041 μs | 1.7334 μs | 19.744 μs | 1.7395 | 7.12 KB | -| PipeWith10TaskAsync | 101.252 μs | 5.3239 μs | 15.4455 μs | 97.842 μs | 4.8828 | 20.53 KB | -| PipeTaskConditionAsync | 24.214 μs | 1.3098 μs | 3.7998 μs | 22.740 μs | 1.8616 | 7.7 KB | -| PipeWith10TaskConditionAsync | 98.953 μs | 3.9903 μs | 11.0570 μs | 95.221 μs | 4.8828 | 20.56 KB | - -``` -BenchmarkDotNet v0.13.10, Windows 10 (10.0.19044.3570/21H2/November2021Update) -Intel Core i7-8565U CPU 1.80GHz (Whiskey Lake), 1 CPU, 8 logical and 4 physical cores -.NET SDK 8.0.100-rc.2.23502.2 - [Host] : .NET Core 3.1.32 (CoreCLR 4.700.22.55902, CoreFX 4.700.22.56512), X64 RyuJIT AVX2 - DefaultJob : .NET Core 3.1.32 (CoreCLR 4.700.22.55902, CoreFX 4.700.22.56512), X64 RyuJIT AVX2 -``` - -| Method | Mean | Error | StdDev | Gen0 | Allocated | -|----------------------------- |----------:|---------:|---------:|--------:|----------:| -| PipeAsync | 14.38 us | 0.225 us | 0.199 us | 1.1597 | 4.77 KB | -| PipeWith10Async | 328.18 us | 6.287 us | 5.880 us | 19.5313 | 81.7 KB | -| PipeWithConditionAsync | 17.11 us | 0.283 us | 0.237 us | 1.4038 | 5.85 KB | -| PipeWith10ConditionAsync | 36.82 us | 0.702 us | 0.657 us | 3.6621 | 15.44 KB | -| PipeWith10ConditionGotoAsync | 58.69 us | 1.103 us | 2.557 us | 5.3101 | 21.8 KB | -| PipeTaskAsync | 37.06 us | 0.720 us | 1.077 us | 1.7090 | 7.18 KB | -| PipeWith10TaskAsync | 222.57 us | 2.935 us | 2.745 us | 4.8828 | 20.52 KB | -| PipeTaskConditionAsync | 42.97 us | 0.906 us | 2.525 us | 1.8921 | 7.84 KB | -| PipeWith10TaskConditionAsync | 224.77 us | 2.119 us | 1.982 us | 4.8828 | 20.54 KB | - ## Code of Conduct [**Top**](#table-of-contents) diff --git a/whatsnewprev.md b/docs/whatsnewprev.md similarity index 73% rename from whatsnewprev.md rename to docs/whatsnewprev.md index d2227b9..9e0d543 100644 --- a/whatsnewprev.md +++ b/docs/whatsnewprev.md @@ -1,6 +1,11 @@ -# PipeAndFilter What's new +# PipeAndFilter What's new [![Build](https://github.com/FRACerqueira/PipeAndFilter/workflows/Build/badge.svg)](https://github.com/FRACerqueira/PipeAndFilter/actions/workflows/build.yml) [![License](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/FRACerqueira/PipeAndFilter/blob/master/LICENSE) [![NuGet](https://img.shields.io/nuget/v/PipeAndFilter)](https://www.nuget.org/packages/PipeAndFilter/) [![Downloads](https://img.shields.io/nuget/dt/PipeAndFilter)](https://www.nuget.org/packages/PipeAndFilter/) + +### V1.0.1 +[**Main**](index.md) | [**Top**](#pipeandfilter-whats-new) + +- First Release G.A \ No newline at end of file