feat: add latency tracking for service import request-reply

This commit is contained in:
Joseph Doherty
2026-02-23 06:03:37 -05:00
parent 4450c27381
commit 86283a7f97
2 changed files with 69 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
using System.Text.Json.Serialization;
namespace NATS.Server.Imports;
public sealed class ServiceLatencyMsg
{
[JsonPropertyName("type")]
public string Type { get; set; } = "io.nats.server.metric.v1.service_latency";
[JsonPropertyName("requestor")]
public string Requestor { get; set; } = string.Empty;
[JsonPropertyName("responder")]
public string Responder { get; set; } = string.Empty;
[JsonPropertyName("status")]
public int Status { get; set; } = 200;
[JsonPropertyName("svc_latency")]
public long ServiceLatencyNanos { get; set; }
[JsonPropertyName("total_latency")]
public long TotalLatencyNanos { get; set; }
}
public static class LatencyTracker
{
public static bool ShouldSample(ServiceLatency latency)
{
if (latency.SamplingPercentage <= 0) return false;
if (latency.SamplingPercentage >= 100) return true;
return Random.Shared.Next(100) < latency.SamplingPercentage;
}
public static ServiceLatencyMsg BuildLatencyMsg(
string requestor, string responder,
TimeSpan serviceLatency, TimeSpan totalLatency)
{
return new ServiceLatencyMsg
{
Requestor = requestor,
Responder = responder,
ServiceLatencyNanos = serviceLatency.Ticks * 100,
TotalLatencyNanos = totalLatency.Ticks * 100,
};
}
}

View File

@@ -124,4 +124,26 @@ public class ResponseRoutingTests
resp2.To.ShouldBe("_INBOX.reply2");
resp1.From.ShouldNotBe(resp2.From);
}
[Fact]
public void LatencyTracker_should_sample_respects_percentage()
{
var latency = new ServiceLatency { SamplingPercentage = 0, Subject = "latency.test" };
LatencyTracker.ShouldSample(latency).ShouldBeFalse();
var latency100 = new ServiceLatency { SamplingPercentage = 100, Subject = "latency.test" };
LatencyTracker.ShouldSample(latency100).ShouldBeTrue();
}
[Fact]
public void LatencyTracker_builds_latency_message()
{
var msg = LatencyTracker.BuildLatencyMsg("requester", "responder",
TimeSpan.FromMilliseconds(5), TimeSpan.FromMilliseconds(10));
msg.Requestor.ShouldBe("requester");
msg.Responder.ShouldBe("responder");
msg.ServiceLatencyNanos.ShouldBeGreaterThan(0);
msg.TotalLatencyNanos.ShouldBeGreaterThan(0);
}
}