1+ using System . Diagnostics ;
12using Foundatio . Mediator . Benchmarks . Messages ;
23using Foundatio . Mediator . Benchmarks . Services ;
34
@@ -7,10 +8,10 @@ namespace Foundatio.Mediator.Benchmarks.Handlers.Foundatio;
78[ Handler ]
89public class FoundatioCommandHandler
910{
10- public Task HandleAsync ( PingCommand command , CancellationToken cancellationToken = default )
11+ public ValueTask HandleAsync ( PingCommand command , CancellationToken cancellationToken = default )
1112 {
12- // Simulate minimal work - no async state machine
13- return Task . CompletedTask ;
13+ // Simulate minimal work
14+ return default ;
1415 }
1516}
1617
@@ -20,28 +21,28 @@ public class FoundatioQueryHandler
2021{
2122 public ValueTask < Order > HandleAsync ( GetOrder query , CancellationToken cancellationToken = default )
2223 {
23- return new ValueTask < Order > ( new Order ( query . Id , 99.99m , DateTime . UtcNow ) ) ;
24+ return ValueTask . FromResult ( new Order ( query . Id , 99.99m , DateTime . UtcNow ) ) ;
2425 }
2526}
2627
2728// Scenario 3: Event handlers (PublishAsync with multiple handlers)
2829[ Handler ]
2930public class FoundatioEventHandler
3031{
31- public Task HandleAsync ( UserRegisteredEvent notification , CancellationToken cancellationToken = default )
32+ public ValueTask HandleAsync ( UserRegisteredEvent notification , CancellationToken cancellationToken = default )
3233 {
33- // Simulate minimal event handling work - returns completed task with no allocation
34- return Task . CompletedTask ;
34+ // Simulate minimal event handling work
35+ return default ;
3536 }
3637}
3738
3839[ Handler ]
3940public class FoundatioSecondEventHandler
4041{
41- public Task HandleAsync ( UserRegisteredEvent notification , CancellationToken cancellationToken = default )
42+ public ValueTask HandleAsync ( UserRegisteredEvent notification , CancellationToken cancellationToken = default )
4243 {
4344 // Second handler listening for the same event
44- return Task . CompletedTask ;
45+ return default ;
4546 }
4647}
4748
@@ -56,52 +57,86 @@ public FoundatioFullQueryHandler(IOrderService orderService)
5657 _orderService = orderService ;
5758 }
5859
59- public async Task < Order > HandleAsync ( GetFullQuery query , CancellationToken cancellationToken = default )
60+ public ValueTask < Order > HandleAsync ( GetFullQuery query , CancellationToken cancellationToken = default )
6061 {
61- return await _orderService . GetOrderAsync ( query . Id , cancellationToken ) ;
62+ return _orderService . GetOrderAsync ( query . Id , cancellationToken ) ;
6263 }
6364}
6465
6566// Scenario 5: Cascading messages - returns tuple with result + events that auto-publish
6667[ Handler ]
6768public class FoundatioCreateOrderHandler
6869{
69- public ( Order order , OrderCreatedEvent evt ) HandleAsync ( CreateOrder command , CancellationToken cancellationToken = default )
70+ public ValueTask < ( Order order , OrderCreatedEvent evt ) > HandleAsync ( CreateOrder command , CancellationToken cancellationToken = default )
7071 {
71- // No async state machine needed
7272 var order = new Order ( 1 , command . Amount , DateTime . UtcNow ) ;
73- return ( order , new OrderCreatedEvent ( order . Id , command . CustomerId ) ) ;
73+ return ValueTask . FromResult ( ( order , new OrderCreatedEvent ( order . Id , command . CustomerId ) ) ) ;
7474 }
7575}
7676
7777// Handlers for the cascaded OrderCreatedEvent
7878[ Handler ]
7979public class FoundatioFirstOrderCreatedHandler
8080{
81- public Task HandleAsync ( OrderCreatedEvent notification , CancellationToken cancellationToken = default )
81+ public ValueTask HandleAsync ( OrderCreatedEvent notification , CancellationToken cancellationToken = default )
8282 {
83- // First handler for order created event - no async state machine
84- return Task . CompletedTask ;
83+ // First handler for order created event
84+ return default ;
8585 }
8686}
8787
8888[ Handler ]
8989public class FoundatioSecondOrderCreatedHandler
9090{
91- public Task HandleAsync ( OrderCreatedEvent notification , CancellationToken cancellationToken = default )
91+ public ValueTask HandleAsync ( OrderCreatedEvent notification , CancellationToken cancellationToken = default )
9292 {
93- // Second handler for order created event - no async state machine
94- return Task . CompletedTask ;
93+ // Second handler for order created event
94+ return default ;
9595 }
9696}
9797
9898// Scenario 6: Short-circuit handler (never actually called due to ShortCircuitMiddleware)
9999[ Handler ]
100100public class FoundatioShortCircuitHandler
101101{
102- public Task < Order > HandleAsync ( GetCachedOrder query , CancellationToken cancellationToken = default )
102+ public ValueTask < Order > HandleAsync ( GetCachedOrder query , CancellationToken cancellationToken = default )
103103 {
104104 // This should never be called - middleware short-circuits before reaching handler
105105 throw new InvalidOperationException ( "Short-circuit middleware should have prevented this call" ) ;
106106 }
107107}
108+
109+ /// <summary>
110+ /// Simple timing middleware for benchmarking - simulates real-world logging/timing middleware.
111+ /// Only applies to GetFullQuery (FullQuery benchmark).
112+ /// </summary>
113+ [ Middleware ]
114+ public static class TimingMiddleware
115+ {
116+ public static Stopwatch Before ( GetFullQuery message , HandlerExecutionInfo info )
117+ {
118+ return Stopwatch . StartNew ( ) ;
119+ }
120+
121+ public static void Finally ( GetFullQuery message , Stopwatch ? stopwatch , HandlerExecutionInfo info )
122+ {
123+ stopwatch ? . Stop ( ) ;
124+ // In real middleware, you'd log here - we just stop the timer for the benchmark
125+ }
126+ }
127+
128+ /// <summary>
129+ /// Short-circuit middleware that immediately returns a cached result without calling the handler.
130+ /// This demonstrates middleware returning early (cache hit, validation success with cached result, etc.)
131+ /// </summary>
132+ [ Middleware ]
133+ public class ShortCircuitMiddleware
134+ {
135+ private static readonly Order _cachedOrder = new ( 999 , 49.99m , DateTime . UtcNow ) ;
136+
137+ public ValueTask < HandlerResult > BeforeAsync ( GetCachedOrder message )
138+ {
139+ // Always short-circuit with cached result - simulates cache hit scenario
140+ return ValueTask . FromResult ( HandlerResult . ShortCircuit ( _cachedOrder ) ) ;
141+ }
142+ }
0 commit comments