perf(metrics): cache MxEventFamily names for per-event metric tags

WorkerClient.StageWorkerEvent and StreamEvents called Enum.ToString per
event (per subscriber on the stream path). MxEventFamilyNames serves the
contract-fixed names from a frozen lookup, falling back to ToString for
undefined values so exported tag values are unchanged.
This commit is contained in:
Joseph Doherty
2026-10-22 06:30:57 -04:00
parent 6ae5ed905f
commit 68d6b5fd6f
4 changed files with 71 additions and 2 deletions
@@ -183,7 +183,7 @@ public sealed class MxAccessGatewayService(
// call is cancelled, instead of leaving it to the transport's own timeout.
await responseStream.WriteAsync(publicEvent, context.CancellationToken).ConfigureAwait(false);
metrics.RecordEventStreamSend(
publicEvent.Family.ToString(),
MxEventFamilyNames.Get(publicEvent.Family),
Stopwatch.GetElapsedTime(sendStartTimestamp));
}
}
@@ -0,0 +1,28 @@
using System.Collections.Frozen;
using ZB.MOM.WW.MxGateway.Contracts.Proto;
namespace ZB.MOM.WW.MxGateway.Server.Metrics;
/// <summary>
/// Cached <see cref="MxEventFamily"/> names for the per-event metric tags.
/// </summary>
/// <remarks>
/// <see cref="Enum.ToString()"/> allocates a new string on every call, and the event-received
/// and stream-send metrics tag every event with its family — once per event at the worker
/// boundary and once per event per subscriber on the stream. The names are fixed by the
/// contract, so they are computed once here. A value the contract does not define falls back
/// to <see cref="Enum.ToString()"/>, which is the same string the uncached call produced.
/// </remarks>
public static class MxEventFamilyNames
{
private static readonly FrozenDictionary<MxEventFamily, string> Names =
Enum.GetValues<MxEventFamily>()
.Distinct()
.ToFrozenDictionary(family => family, family => family.ToString());
/// <summary>Gets the name of an event family.</summary>
/// <param name="family">The event family.</param>
/// <returns>The family's name, identical to <see cref="Enum.ToString()"/>.</returns>
public static string Get(MxEventFamily family) =>
Names.TryGetValue(family, out string? name) ? name : family.ToString();
}
@@ -692,7 +692,7 @@ public sealed class WorkerClient : IWorkerClient
{
if (workerEvent.Event is not null)
{
_metrics?.EventReceived(SessionId, workerEvent.Event.Family.ToString());
_metrics?.EventReceived(SessionId, MxEventFamilyNames.Get(workerEvent.Event.Family));
}
if (_eventStaging.Writer.TryWrite(workerEvent))