Skip to content

Commit 6561a7c

Browse files
committed
Various benchmark updates
1 parent 60224bf commit 6561a7c

35 files changed

Lines changed: 2240 additions & 378 deletions

benchmarks/Foundatio.Mediator.Benchmarks/CoreBenchmarks.cs

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ public void Setup()
9595
cfg.AddConsumer<Handlers.MassTransit.MassTransitOrderCreatedConsumer1>();
9696
cfg.AddConsumer<Handlers.MassTransit.MassTransitOrderCreatedConsumer2>();
9797
cfg.AddConsumer<Handlers.MassTransit.MassTransitShortCircuitConsumer>();
98+
// Register timing filter for GetFullQuery and short-circuit filter for GetCachedOrder
99+
cfg.ConfigureMediator((context, mcfg) =>
100+
{
101+
mcfg.UseConsumeFilter(typeof(Handlers.MassTransit.MassTransitTimingFilter<>), context);
102+
mcfg.UseConsumeFilter(typeof(Handlers.MassTransit.MassTransitShortCircuitFilter<>), context);
103+
});
98104
});
99105
_masstransitServices = masstransitServices.BuildServiceProvider();
100106
_masstransitMediator = _masstransitServices.GetRequiredService<MassTransit.Mediator.IMediator>();
@@ -104,6 +110,8 @@ public void Setup()
104110
mediatorNetServices.AddSingleton<IOrderService, OrderService>();
105111
// Register short-circuit behavior before AddMediator so it's available in the pipeline
106112
mediatorNetServices.AddSingleton<MediatorLib.IPipelineBehavior<MediatorNetGetCachedOrder, Order>, MediatorNetShortCircuitBehavior>();
113+
// Register timing behavior for GetFullQuery to match Foundatio's middleware
114+
mediatorNetServices.AddSingleton<MediatorLib.IPipelineBehavior<MediatorNetGetFullQuery, Order>, MediatorNetTimingBehavior>();
107115
mediatorNetServices.AddMediator(options =>
108116
{
109117
options.ServiceLifetime = ServiceLifetime.Singleton;
@@ -132,6 +140,8 @@ public void Setup()
132140
.IncludeType<Handlers.Wolverine.WolverineShortCircuitHandler>();
133141
// Register short-circuit middleware for GetCachedOrder
134142
opts.Policies.ForMessagesOfType<GetCachedOrder>().AddMiddleware(typeof(Handlers.Wolverine.WolverineShortCircuitMiddleware));
143+
// Register timing middleware for GetFullQuery to match Foundatio's middleware
144+
opts.Policies.ForMessagesOfType<GetFullQuery>().AddMiddleware(typeof(Handlers.Wolverine.WolverineTimingMiddleware));
135145
})
136146
.Build();
137147
_wolverineHost.Start();
@@ -157,66 +167,66 @@ public async Task Cleanup()
157167

158168
// Baseline: Direct method calls (no mediator overhead)
159169
[Benchmark]
160-
public async Task Direct_Command()
170+
public ValueTask Direct_Command()
161171
{
162-
await _directCommandHandler.HandleAsync(_pingCommand);
172+
return _directCommandHandler.HandleAsync(_pingCommand);
163173
}
164174

165175
[Benchmark]
166-
public async Task<Order> Direct_Query()
176+
public ValueTask<Order> Direct_Query()
167177
{
168-
return await _directQueryHandler.HandleAsync(_getOrder);
178+
return _directQueryHandler.HandleAsync(_getOrder);
169179
}
170180

171181
[Benchmark]
172-
public async Task Direct_Publish()
182+
public ValueTask Direct_Publish()
173183
{
174-
await _directEventHandler.HandleAsync(_userRegisteredEvent);
184+
return _directEventHandler.HandleAsync(_userRegisteredEvent);
175185
}
176186

177187

178188
// Scenario 1: InvokeAsync without response (Command)
179189
[Benchmark]
180-
public async Task Foundatio_Command()
190+
public ValueTask Foundatio_Command()
181191
{
182-
await _foundatioMediator.InvokeAsync(_pingCommand);
192+
return _foundatioMediator.InvokeAsync(_pingCommand);
183193
}
184194

185195
[Benchmark]
186-
public async Task MediatR_Command()
196+
public Task MediatR_Command()
187197
{
188-
await _mediatrMediator.Send(_pingCommand);
198+
return _mediatrMediator.Send(_pingCommand);
189199
}
190200

191201
[Benchmark]
192-
public async Task MassTransit_Command()
202+
public Task MassTransit_Command()
193203
{
194-
await _masstransitMediator.Send(_pingCommand);
204+
return _masstransitMediator.Send(_pingCommand);
195205
}
196206

197207
[Benchmark]
198-
public async Task Wolverine_Command()
208+
public Task Wolverine_Command()
199209
{
200-
await _wolverineBus.InvokeAsync(_pingCommand);
210+
return _wolverineBus.InvokeAsync(_pingCommand);
201211
}
202212

203213
[Benchmark]
204-
public async Task MediatorNet_Command()
214+
public ValueTask<global::Mediator.Unit> MediatorNet_Command()
205215
{
206-
await _mediatorNetMediator.Send(_mediatorNetPingCommand);
216+
return _mediatorNetMediator.Send(_mediatorNetPingCommand);
207217
}
208218

209219
// Scenario 2: InvokeAsync<T> (Query)
210220
[Benchmark]
211-
public async Task<Order> Foundatio_Query()
221+
public ValueTask<Order> Foundatio_Query()
212222
{
213-
return await _foundatioMediator.InvokeAsync<Order>(_getOrder);
223+
return _foundatioMediator.InvokeAsync<Order>(_getOrder);
214224
}
215225

216226
[Benchmark]
217-
public async Task<Order> MediatR_Query()
227+
public Task<Order> MediatR_Query()
218228
{
219-
return await _mediatrMediator.Send(_getOrder);
229+
return _mediatrMediator.Send(_getOrder);
220230
}
221231

222232
[Benchmark]
@@ -228,46 +238,46 @@ public async Task<Order> MassTransit_Query()
228238
}
229239

230240
[Benchmark]
231-
public async Task<Order?> Wolverine_Query()
241+
public Task<Order?> Wolverine_Query()
232242
{
233-
return await _wolverineBus.InvokeAsync<Order>(_getOrder);
243+
return _wolverineBus.InvokeAsync<Order?>(_getOrder);
234244
}
235245

236246
[Benchmark]
237-
public async Task<Order> MediatorNet_Query()
247+
public ValueTask<Order> MediatorNet_Query()
238248
{
239-
return await _mediatorNetMediator.Send(_mediatorNetGetOrder);
249+
return _mediatorNetMediator.Send(_mediatorNetGetOrder);
240250
}
241251

242252
// Scenario 3: PublishAsync with a single handler
243253
[Benchmark]
244-
public async Task Foundatio_Publish()
254+
public ValueTask Foundatio_Publish()
245255
{
246-
await _foundatioMediator.PublishAsync(_userRegisteredEvent);
256+
return _foundatioMediator.PublishAsync(_userRegisteredEvent);
247257
}
248258

249259
[Benchmark]
250-
public async Task MediatR_Publish()
260+
public Task MediatR_Publish()
251261
{
252-
await _mediatrMediator.Publish(_userRegisteredEvent);
262+
return _mediatrMediator.Publish(_userRegisteredEvent);
253263
}
254264

255265
[Benchmark]
256-
public async Task MassTransit_Publish()
266+
public Task MassTransit_Publish()
257267
{
258-
await _masstransitMediator.Publish(_userRegisteredEvent);
268+
return _masstransitMediator.Publish(_userRegisteredEvent);
259269
}
260270

261271
[Benchmark]
262-
public async Task Wolverine_Publish()
272+
public ValueTask Wolverine_Publish()
263273
{
264-
await _wolverineBus.PublishAsync(_userRegisteredEvent);
274+
return _wolverineBus.PublishAsync(_userRegisteredEvent);
265275
}
266276

267277
[Benchmark]
268-
public async Task MediatorNet_Publish()
278+
public ValueTask MediatorNet_Publish()
269279
{
270-
await _mediatorNetMediator.Publish(_mediatorNetUserRegisteredEvent);
280+
return _mediatorNetMediator.Publish(_mediatorNetUserRegisteredEvent);
271281
}
272282

273283
// Scenario 4: InvokeAsync<T> with DI (Query with dependency injection and middleware)
@@ -288,9 +298,9 @@ public async Task<Order> Direct_FullQuery()
288298
}
289299

290300
[Benchmark]
291-
public async Task<Order> Foundatio_FullQuery()
301+
public ValueTask<Order> Foundatio_FullQuery()
292302
{
293-
return await _foundatioMediator.InvokeAsync<Order>(_getFullQuery);
303+
return _foundatioMediator.InvokeAsync<Order>(_getFullQuery);
294304
}
295305

296306
[Benchmark]
@@ -314,25 +324,25 @@ public async Task<Order> MassTransit_FullQuery()
314324
}
315325

316326
[Benchmark]
317-
public async Task<Order> MediatorNet_FullQuery()
327+
public ValueTask<Order> MediatorNet_FullQuery()
318328
{
319-
return await _mediatorNetMediator.Send(_mediatorNetGetFullQuery);
329+
return _mediatorNetMediator.Send(_mediatorNetGetFullQuery);
320330
}
321331

322332
// Scenario 5: Cascading messages - invoke returns result and auto-publishes events to multiple handlers
323333
[Benchmark]
324334
public async Task<Order> Direct_CascadingMessages()
325335
{
326-
var (order, evt) = _directCreateOrderHandler.HandleAsync(_createOrder);
336+
var (order, evt) = await _directCreateOrderHandler.HandleAsync(_createOrder);
327337
await _directOrderCreatedHandler1.HandleAsync(evt);
328338
await _directOrderCreatedHandler2.HandleAsync(evt);
329339
return order;
330340
}
331341

332342
[Benchmark]
333-
public async Task<Order> Foundatio_CascadingMessages()
343+
public ValueTask<Order> Foundatio_CascadingMessages()
334344
{
335-
return await _foundatioMediator.InvokeAsync<Order>(_createOrder);
345+
return _foundatioMediator.InvokeAsync<Order>(_createOrder);
336346
}
337347

338348
[Benchmark]
@@ -356,26 +366,26 @@ public async Task<Order> MassTransit_CascadingMessages()
356366
}
357367

358368
[Benchmark]
359-
public async Task<Order> MediatorNet_CascadingMessages()
369+
public ValueTask<Order> MediatorNet_CascadingMessages()
360370
{
361-
return await _mediatorNetMediator.Send(_mediatorNetCreateOrder);
371+
return _mediatorNetMediator.Send(_mediatorNetCreateOrder);
362372
}
363373

364374
// Scenario 6: Short-circuit middleware - returns cached result, handler is never invoked
365375
// Tests the cost of short-circuiting via middleware (caching, validation, auth, etc.)
366376
private static readonly Order _cachedOrder = new(999, 49.99m, DateTime.UtcNow);
367377

368378
[Benchmark]
369-
public Task<Order> Direct_ShortCircuit()
379+
public ValueTask<Order> Direct_ShortCircuit()
370380
{
371381
// Simulate ShortCircuitMiddleware.Before returning cached result
372-
return Task.FromResult(_cachedOrder);
382+
return ValueTask.FromResult(_cachedOrder);
373383
}
374384

375385
[Benchmark]
376-
public async Task<Order> Foundatio_ShortCircuit()
386+
public ValueTask<Order> Foundatio_ShortCircuit()
377387
{
378-
return await _foundatioMediator.InvokeAsync<Order>(_getCachedOrder);
388+
return _foundatioMediator.InvokeAsync<Order>(_getCachedOrder);
379389
}
380390

381391
[Benchmark]
@@ -399,8 +409,8 @@ public async Task<Order> MassTransit_ShortCircuit()
399409
}
400410

401411
[Benchmark]
402-
public async Task<Order> MediatorNet_ShortCircuit()
412+
public ValueTask<Order> MediatorNet_ShortCircuit()
403413
{
404-
return await _mediatorNetMediator.Send(_mediatorNetGetCachedOrder);
414+
return _mediatorNetMediator.Send(_mediatorNetGetCachedOrder);
405415
}
406416
}

benchmarks/Foundatio.Mediator.Benchmarks/Foundatio.Mediator.Benchmarks.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<!-- Foundatio generator options -->
1717
<MediatorHandlerLifetime>None</MediatorHandlerLifetime>
1818
<MediatorDisableInterceptors>false</MediatorDisableInterceptors>
19-
<MediatorDisableOpenTelemetry>false</MediatorDisableOpenTelemetry>
19+
<MediatorDisableOpenTelemetry>true</MediatorDisableOpenTelemetry>
2020
<MediatorDisableConventionalDiscovery>true</MediatorDisableConventionalDiscovery>
2121
</PropertyGroup>
2222

@@ -42,7 +42,7 @@
4242
<ItemGroup>
4343
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
4444
<PackageReference Include="MassTransit" Version="8.5.7" />
45-
<PackageReference Include="MediatR" Version="14.0.0" />
45+
<PackageReference Include="MediatR" Version="12.5.0" />
4646
<PackageReference Include="WolverineFx" Version="5.9.2" />
4747
<PackageReference Include="Mediator.Abstractions" Version="3.0.1" />
4848
<PackageReference Include="Mediator.SourceGenerator" Version="3.0.1">

benchmarks/Foundatio.Mediator.Benchmarks/FoundatioBenchmarks.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ public void Cleanup()
4040
}
4141

4242
[Benchmark]
43-
public async Task Command()
43+
public ValueTask Command()
4444
{
45-
await _foundatioMediator.InvokeAsync(_pingCommand);
45+
return _foundatioMediator.InvokeAsync(_pingCommand);
4646
}
4747

4848
[Benchmark]
@@ -58,20 +58,20 @@ public ValueTask Publish()
5858
}
5959

6060
[Benchmark]
61-
public async Task<Order> FullQuery()
61+
public ValueTask<Order> FullQuery()
6262
{
63-
return await _foundatioMediator.InvokeAsync<Order>(_getFullQuery);
63+
return _foundatioMediator.InvokeAsync<Order>(_getFullQuery);
6464
}
6565

6666
[Benchmark]
67-
public async Task<Order> CascadingMessages()
67+
public ValueTask<Order> CascadingMessages()
6868
{
69-
return await _foundatioMediator.InvokeAsync<Order>(_createOrder);
69+
return _foundatioMediator.InvokeAsync<Order>(_createOrder);
7070
}
7171

7272
[Benchmark]
73-
public async Task<Order> ShortCircuit()
73+
public ValueTask<Order> ShortCircuit()
7474
{
75-
return await _foundatioMediator.InvokeAsync<Order>(_getCachedOrder);
75+
return _foundatioMediator.InvokeAsync<Order>(_getCachedOrder);
7676
}
7777
}

0 commit comments

Comments
 (0)