feat(notification-outbox): per-site KPI snapshot type + repository contract
This commit is contained in:
@@ -62,6 +62,15 @@ public interface INotificationOutboxRepository
|
|||||||
Task<NotificationKpiSnapshot> ComputeKpisAsync(
|
Task<NotificationKpiSnapshot> ComputeKpisAsync(
|
||||||
DateTimeOffset stuckCutoff, DateTimeOffset deliveredSince, CancellationToken cancellationToken = default);
|
DateTimeOffset stuckCutoff, DateTimeOffset deliveredSince, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes a point-in-time <see cref="SiteNotificationKpiSnapshot"/> per source site.
|
||||||
|
/// Sites with no notification rows at all are omitted. The stuck and delivered cutoffs
|
||||||
|
/// are supplied by the caller; the current time used for <c>OldestPendingAge</c> is
|
||||||
|
/// captured inside the method.
|
||||||
|
/// </summary>
|
||||||
|
Task<IReadOnlyList<SiteNotificationKpiSnapshot>> ComputePerSiteKpisAsync(
|
||||||
|
DateTimeOffset stuckCutoff, DateTimeOffset deliveredSince, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Persists pending changes tracked on the underlying context. Use this when staging
|
/// Persists pending changes tracked on the underlying context. Use this when staging
|
||||||
/// multiple changes for a single commit; the individual mutating methods on this
|
/// multiple changes for a single commit; the individual mutating methods on this
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
namespace ScadaLink.Commons.Types.Notifications;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Point-in-time notification-outbox metrics scoped to a single source site.
|
||||||
|
/// The per-site counterpart of <see cref="NotificationKpiSnapshot"/>; surfaced
|
||||||
|
/// in the per-site breakdown table on the Notification KPIs page.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="SourceSiteId">The site identifier these metrics are scoped to.</param>
|
||||||
|
/// <param name="QueueDepth">Count of this site's non-terminal rows (Pending + Retrying).</param>
|
||||||
|
/// <param name="StuckCount">
|
||||||
|
/// Count of this site's non-terminal rows whose <c>CreatedAt</c> is older than the stuck cutoff.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="ParkedCount">Count of this site's rows in the Parked status.</param>
|
||||||
|
/// <param name="DeliveredLastInterval">
|
||||||
|
/// Count of this site's Delivered rows whose <c>DeliveredAt</c> is at or after the
|
||||||
|
/// "delivered since" timestamp.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="OldestPendingAge">
|
||||||
|
/// Age of this site's oldest non-terminal row, or <c>null</c> when it has none.
|
||||||
|
/// </param>
|
||||||
|
public record SiteNotificationKpiSnapshot(
|
||||||
|
string SourceSiteId,
|
||||||
|
int QueueDepth,
|
||||||
|
int StuckCount,
|
||||||
|
int ParkedCount,
|
||||||
|
int DeliveredLastInterval,
|
||||||
|
TimeSpan? OldestPendingAge);
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using ScadaLink.Commons.Types.Notifications;
|
||||||
|
|
||||||
|
namespace ScadaLink.Commons.Tests.Types;
|
||||||
|
|
||||||
|
public class SiteNotificationKpiSnapshotTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Constructor_AssignsAllMembers()
|
||||||
|
{
|
||||||
|
var snapshot = new SiteNotificationKpiSnapshot(
|
||||||
|
SourceSiteId: "plant-a",
|
||||||
|
QueueDepth: 5,
|
||||||
|
StuckCount: 2,
|
||||||
|
ParkedCount: 1,
|
||||||
|
DeliveredLastInterval: 40,
|
||||||
|
OldestPendingAge: TimeSpan.FromMinutes(12));
|
||||||
|
|
||||||
|
Assert.Equal("plant-a", snapshot.SourceSiteId);
|
||||||
|
Assert.Equal(5, snapshot.QueueDepth);
|
||||||
|
Assert.Equal(2, snapshot.StuckCount);
|
||||||
|
Assert.Equal(1, snapshot.ParkedCount);
|
||||||
|
Assert.Equal(40, snapshot.DeliveredLastInterval);
|
||||||
|
Assert.Equal(TimeSpan.FromMinutes(12), snapshot.OldestPendingAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OldestPendingAge_IsNullableForSitesWithNoBacklog()
|
||||||
|
{
|
||||||
|
var snapshot = new SiteNotificationKpiSnapshot("plant-b", 0, 0, 0, 0, null);
|
||||||
|
Assert.Null(snapshot.OldestPendingAge);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user