using NATS.Client.Core; using NATS.Server.Benchmark.Tests.Harness; using NATS.Server.Benchmark.Tests.Infrastructure; using Xunit.Abstractions; namespace NATS.Server.Benchmark.Tests.RequestReply; [Collection("Benchmark-Core")] public class SingleClientLatencyTests(CoreServerPairFixture fixture, ITestOutputHelper output) { private readonly BenchmarkRunner _runner = new() { WarmupCount = 500, MeasurementCount = 10_000 }; [Fact] [Trait("Category", "Benchmark")] public async Task RequestReply_SingleClient_128B() { const int payloadSize = 128; const string subject = "bench.reqrep.single"; var dotnetResult = await RunLatency("Request-Reply Single (128B)", "DotNet", subject, payloadSize, fixture.CreateDotNetClient); if (fixture.GoAvailable) { var goResult = await RunLatency("Request-Reply Single (128B)", "Go", subject, payloadSize, fixture.CreateGoClient); BenchmarkResultWriter.WriteComparison(output, goResult, dotnetResult); } else { BenchmarkResultWriter.WriteSingle(output, dotnetResult); } } private async Task RunLatency(string name, string serverType, string subject, int payloadSize, Func createClient) { var payload = new byte[payloadSize]; await using var serviceClient = createClient(); await using var requestClient = createClient(); await serviceClient.ConnectAsync(); await requestClient.ConnectAsync(); // Start service responder var sub = await serviceClient.SubscribeCoreAsync(subject); var responderTask = Task.Run(async () => { await foreach (var msg in sub.Msgs.ReadAllAsync()) { if (msg.ReplyTo is not null) await serviceClient.PublishAsync(msg.ReplyTo, payload); } }); await Task.Delay(50); var result = await _runner.MeasureLatencyAsync(name, serverType, payloadSize, async _ => { await requestClient.RequestAsync(subject, payload); }); await sub.UnsubscribeAsync(); return result; } }