Skip to content

Commit a29adc9

Browse files
committed
Improves pipeline performance and updates dependencies
Optimizes the `ProcessBlockAsync` method to avoid async state machine when the function completes synchronously, reducing overhead and improving pipeline throughput. Also updates Microsoft dependency packages to the latest 9.0.7 versions and testing libraries to their newest stable releases.
1 parent 25f3746 commit a29adc9

File tree

13 files changed

+88
-34
lines changed

13 files changed

+88
-34
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ Some key features are:
2424
Pipelines provide a structured approach to managing complex processes, promoting [SOLID](https://en.wikipedia.org/wiki/SOLID)
2525
principles, including Inversion of Control (IoC) and Separation of Concerns (SoC). They enable composability, making it easier
2626
to build, test, and maintain your code. By extending the benefits of middleware and request-response pipelines throughout your
27-
application, you achieve greater modularity, scalability, and flexibility. This is especially critical in domains such as
28-
healthcare, compliance auditing, identity and roles, and high-security environments where clear boundaries and responsibilities
27+
application, you achieve greater modularity, scalability, and flexibility. This is particularly important in domains that demand
28+
compliance, auditing, strong identity and role management, or high-security standards—where clear boundaries and responsibilities
2929
are essential. Hyperbee.Pipeline ensures that the advantages of pipelines and middleware are not abandoned at the controller
3030
implementation, addressing a common gap in many frameworks. By using a functional approach, Hyperbee.Pipeline ensures that your
3131
pipelines are not only robust and maintainable but also highly adaptable to changing requirements.

src/Hyperbee.Pipeline.Auth/Hyperbee.Pipeline.Auth.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<Pack>True</Pack>
3333
<PackagePath>\</PackagePath>
3434
</None>
35-
<PackageReference Include="Microsoft.AspNetCore.Http.Connections.Common" Version="9.0.4" />
35+
<PackageReference Include="Microsoft.AspNetCore.Http.Connections.Common" Version="9.0.7" />
3636
<ProjectReference Include="..\Hyperbee.Pipeline\Hyperbee.Pipeline.csproj" />
3737
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="8.0.0">
3838
<PrivateAssets>all</PrivateAssets>

src/Hyperbee.Pipeline/Binders/Abstractions/BlockBinder.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Hyperbee.Pipeline.Context;
2+
using System.Threading.Tasks;
23

34
namespace Hyperbee.Pipeline.Binders.Abstractions;
45

@@ -13,8 +14,14 @@ protected BlockBinder( FunctionAsync<TStart, TOutput> function, Action<IPipeline
1314
// use cases where the next argument is not the same as the output type
1415
// like ReduceBlockBinder and ForEachBlockBinder
1516

16-
protected virtual async Task<TNext> ProcessBlockAsync<TArgument, TNext>( FunctionAsync<TArgument, TNext> blockFunction, IPipelineContext context, TArgument nextArgument )
17+
protected virtual ValueTask<TNext> ProcessBlockAsync<TArgument, TNext>( FunctionAsync<TArgument, TNext> blockFunction, IPipelineContext context, TArgument nextArgument )
1718
{
18-
return await blockFunction( context, nextArgument ).ConfigureAwait( false );
19+
// If the function completes synchronously, avoid async state machine
20+
var task = blockFunction( context, nextArgument );
21+
22+
if (task.IsCompletedSuccessfully)
23+
return new ValueTask<TNext>(task.Result);
24+
25+
return new ValueTask<TNext>(task);
1926
}
2027
}

src/Hyperbee.Pipeline/Binders/Abstractions/ConditionalBlockBinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ protected ConditionalBlockBinder( Function<TOutput, bool> condition, FunctionAsy
1313
Condition = condition;
1414
}
1515

16-
protected override async Task<TNext> ProcessBlockAsync<TArgument, TNext>( FunctionAsync<TArgument, TNext> blockFunction, IPipelineContext context, TArgument nextArgument )
16+
protected override async ValueTask<TNext> ProcessBlockAsync<TArgument, TNext>( FunctionAsync<TArgument, TNext> blockFunction, IPipelineContext context, TArgument nextArgument )
1717
{
1818
if ( Condition != null && !Condition( context, CastTypeArg<TArgument, TOutput>( nextArgument ) ) )
1919
{

src/Hyperbee.Pipeline/Binders/ForEachBlockBinder.cs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using Hyperbee.Pipeline.Binders.Abstractions;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
24

35
namespace Hyperbee.Pipeline.Binders;
46

@@ -10,7 +12,6 @@ public ForEachBlockBinder( FunctionAsync<TStart, TOutput> function )
1012
}
1113

1214
public FunctionAsync<TStart, TOutput> Bind( FunctionAsync<TElement, object> next )
13-
1415
{
1516
return async ( context, argument ) =>
1617
{
@@ -19,11 +20,33 @@ public FunctionAsync<TStart, TOutput> Bind( FunctionAsync<TElement, object> next
1920
if ( canceled )
2021
return default;
2122

22-
var nextArguments = (IEnumerable<TElement>) nextArgument;
23-
24-
foreach ( var elementArgument in nextArguments )
23+
if (nextArgument is IList<TElement> list)
24+
{
25+
for (int i = 0; i < list.Count; i++)
26+
{
27+
if (context.CancellationToken.IsCancellationRequested)
28+
break;
29+
await ProcessBlockAsync(next, context, list[i]).ConfigureAwait(false);
30+
}
31+
}
32+
else if (nextArgument is TElement[] array)
2533
{
26-
await ProcessBlockAsync( next, context, elementArgument ).ConfigureAwait( false );
34+
for (int i = 0; i < array.Length; i++)
35+
{
36+
if (context.CancellationToken.IsCancellationRequested)
37+
break;
38+
await ProcessBlockAsync(next, context, array[i]).ConfigureAwait(false);
39+
}
40+
}
41+
else if (nextArgument is IEnumerable<TElement> enumerable)
42+
{
43+
foreach (var elementArgument in enumerable)
44+
{
45+
if (context.CancellationToken.IsCancellationRequested)
46+
break;
47+
48+
await ProcessBlockAsync(next, context, elementArgument).ConfigureAwait(false);
49+
}
2750
}
2851

2952
return nextArgument;

src/Hyperbee.Pipeline/Binders/ReduceBlockBinder.cs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using Hyperbee.Pipeline.Binders.Abstractions;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
24

35
namespace Hyperbee.Pipeline.Binders;
46

@@ -21,14 +23,37 @@ public FunctionAsync<TStart, TNext> Bind( FunctionAsync<TElement, TNext> next )
2123
if ( canceled )
2224
return default;
2325

24-
var nextArguments = (IEnumerable<TElement>) nextArgument;
25-
var accumulator = default( TNext );
26-
27-
// Process each element and apply the reducer
28-
foreach ( var elementArgument in nextArguments )
26+
TNext accumulator = default;
27+
if (nextArgument is IList<TElement> list)
28+
{
29+
for (int i = 0; i < list.Count; i++)
30+
{
31+
if (context.CancellationToken.IsCancellationRequested)
32+
break;
33+
var result = await ProcessBlockAsync(next, context, list[i]).ConfigureAwait(false);
34+
accumulator = Reducer(accumulator, result);
35+
}
36+
}
37+
else if (nextArgument is TElement[] array)
38+
{
39+
for (int i = 0; i < array.Length; i++)
40+
{
41+
if (context.CancellationToken.IsCancellationRequested)
42+
break;
43+
var result = await ProcessBlockAsync(next, context, array[i]).ConfigureAwait(false);
44+
accumulator = Reducer(accumulator, result);
45+
}
46+
}
47+
else if (nextArgument is IEnumerable<TElement> enumerable)
2948
{
30-
var result = await ProcessBlockAsync( next, context, elementArgument ).ConfigureAwait( false );
31-
accumulator = Reducer( accumulator, result );
49+
foreach (var elementArgument in enumerable)
50+
{
51+
if (context.CancellationToken.IsCancellationRequested)
52+
break;
53+
54+
var result = await ProcessBlockAsync(next, context, elementArgument).ConfigureAwait(false);
55+
accumulator = Reducer(accumulator, result);
56+
}
3257
}
3358

3459
return accumulator;

src/Hyperbee.Pipeline/Builders/BlockBuilderFactory.cs

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/Hyperbee.Pipeline/Hyperbee.Pipeline.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
<PrivateAssets>all</PrivateAssets>
3131
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3232
</PackageReference>
33-
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.4" />
34-
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.4" />
33+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.7" />
34+
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.7" />
3535
</ItemGroup>
3636
</Project>

src/Hyperbee.Pipline.Caching/Hyperbee.Pipeline.Caching.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
<PrivateAssets>all</PrivateAssets>
4040
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
4141
</PackageReference>
42-
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.4" />
42+
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.7" />
4343
</ItemGroup>
4444

4545
</Project>

test/Hyperbee.Pipeline.Auth.Tests/Hyperbee.Pipeline.Auth.Tests.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
<PrivateAssets>all</PrivateAssets>
1414
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1515
</PackageReference>
16-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
17-
<PackageReference Include="MSTest.TestAdapter" Version="3.8.3" />
18-
<PackageReference Include="MSTest.TestFramework" Version="3.8.3" />
16+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
17+
<PackageReference Include="MSTest.TestAdapter" Version="3.9.3" />
18+
<PackageReference Include="MSTest.TestFramework" Version="3.9.3" />
1919
<PackageReference Include="NSubstitute" Version="5.3.0" />
2020
</ItemGroup>
2121

0 commit comments

Comments
 (0)