9cff87fe85
Remove project bookkeeping citations from shipped code comments across the solution: hyphenated task IDs (WP-14, StoreAndForward-025), milestone/task/ issue refs (M3, Task 4, Audit Log #23, #21), Bundle X task-bundle labels, and C/D/K/S/T phase labels. Comment text only — no code logic, string/log literals, or XML-doc structure changed. Genuine descriptions are preserved (only the citation is stripped), and technical lookalikes are retained (UTF-8, SHA-256, T00:00:00, M365, UTC-5, pre-C4/pre-C5 schema versions). Flagged by the new CommentChecker TaskReferenceInComment / TrackingReferenceInComment checks plus targeted grep passes; full solution builds clean, append-only guard tests pass.
126 lines
6.5 KiB
C#
126 lines
6.5 KiB
C#
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
|
|
|
|
/// <summary>
|
|
/// Operational-state data access for the central <c>SiteCalls</c> table.
|
|
/// One row per
|
|
/// <see cref="TrackedOperationId"/>; sites remain the source of truth and this
|
|
/// table is an eventually-consistent mirror fed by best-effort gRPC telemetry
|
|
/// plus periodic reconciliation pulls.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Unlike the partitioned append-only <c>AuditLog</c>, this table holds
|
|
/// mutable operational state. <see cref="UpsertAsync"/> is insert-if-not-exists
|
|
/// then monotonic update — a status update with rank less than or equal to the
|
|
/// stored status is a silent no-op so out-of-order telemetry, duplicate gRPC
|
|
/// packets, and reconciliation pulls can all feed the same writer without
|
|
/// rolling state backward.
|
|
/// </para>
|
|
/// <para>
|
|
/// Status rank for monotonic comparison (lower wins): <c>Submitted=0,
|
|
/// Forwarded=1, Attempted=2, Skipped=2, Delivered=3, Failed=3, Parked=3,
|
|
/// Discarded=3</c>. Terminal statuses share rank 3 and are mutually exclusive
|
|
/// — an attempt to upsert e.g. <c>Delivered</c> over an existing <c>Parked</c>
|
|
/// row is a no-op.
|
|
/// </para>
|
|
/// </remarks>
|
|
public interface ISiteCallAuditRepository
|
|
{
|
|
/// <summary>
|
|
/// Inserts <paramref name="siteCall"/> if no row with the same
|
|
/// <see cref="SiteCall.TrackedOperationId"/> exists; otherwise updates the
|
|
/// existing row IF AND ONLY IF the incoming status' rank strictly exceeds
|
|
/// the stored status' rank. Out-of-order / duplicate updates are silently
|
|
/// dropped (monotonic forward-only progression).
|
|
/// </summary>
|
|
/// <param name="siteCall">The site call row to insert or monotonically update.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
|
Task UpsertAsync(SiteCall siteCall, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Returns the row for the given id, or <c>null</c> if none exists.
|
|
/// </summary>
|
|
/// <param name="id">The tracked operation id to look up.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
/// <returns>A task that resolves to the matching <see cref="SiteCall"/>, or <c>null</c> if no row exists.</returns>
|
|
Task<SiteCall?> GetAsync(TrackedOperationId id, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Returns up to <see cref="SiteCallPaging.PageSize"/> rows matching
|
|
/// <paramref name="filter"/>, ordered by <c>(CreatedAtUtc DESC,
|
|
/// TrackedOperationId DESC)</c>. Use keyset paging via
|
|
/// <see cref="SiteCallPaging.AfterCreatedAtUtc"/> + <see cref="SiteCallPaging.AfterId"/>
|
|
/// to fetch subsequent pages.
|
|
/// </summary>
|
|
/// <param name="filter">Filter criteria for the query.</param>
|
|
/// <param name="paging">Keyset paging parameters.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
/// <returns>A task that resolves to a page of <see cref="SiteCall"/> rows matching the filter, ordered by creation time descending.</returns>
|
|
Task<IReadOnlyList<SiteCall>> QueryAsync(
|
|
SiteCallQueryFilter filter,
|
|
SiteCallPaging paging,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes terminal rows whose <see cref="SiteCall.TerminalAtUtc"/> is
|
|
/// strictly older than <paramref name="olderThanUtc"/>. Non-terminal rows
|
|
/// (TerminalAtUtc IS NULL) are NEVER purged. Returns the number of rows
|
|
/// deleted.
|
|
/// </summary>
|
|
/// <param name="olderThanUtc">UTC cutoff; terminal rows older than this are deleted.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
/// <returns>A task that resolves to the number of rows deleted.</returns>
|
|
Task<int> PurgeTerminalAsync(DateTime olderThanUtc, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Computes a point-in-time global <see cref="SiteCallKpiSnapshot"/> from the
|
|
/// <c>SiteCalls</c> table. Counts are aggregated server-side (no row
|
|
/// materialisation): <c>StuckCount</c> uses <paramref name="stuckCutoff"/>;
|
|
/// <c>FailedLastInterval</c> / <c>DeliveredLastInterval</c> use
|
|
/// <paramref name="intervalSince"/>; the current time for <c>OldestPendingAge</c>
|
|
/// is captured inside the method.
|
|
/// </summary>
|
|
/// <param name="stuckCutoff">UTC threshold for classifying a row as stuck.</param>
|
|
/// <param name="intervalSince">UTC start of the delivered/failed interval window.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
/// <returns>A task that resolves to a global <see cref="SiteCallKpiSnapshot"/> computed from the current table state.</returns>
|
|
Task<SiteCallKpiSnapshot> ComputeKpisAsync(
|
|
DateTime stuckCutoff,
|
|
DateTime intervalSince,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Computes a point-in-time <see cref="SiteCallSiteKpiSnapshot"/> per source
|
|
/// site. Sites with no <c>SiteCalls</c> rows at all are omitted. The stuck
|
|
/// cutoff and interval bounds are interpreted as in <see cref="ComputeKpisAsync"/>.
|
|
/// </summary>
|
|
/// <param name="stuckCutoff">UTC threshold for classifying a row as stuck.</param>
|
|
/// <param name="intervalSince">UTC start of the delivered/failed interval window.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
/// <returns>A task that resolves to a per-site KPI list; sites with no rows are omitted.</returns>
|
|
Task<IReadOnlyList<SiteCallSiteKpiSnapshot>> ComputePerSiteKpisAsync(
|
|
DateTime stuckCutoff,
|
|
DateTime intervalSince,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Computes a point-in-time <see cref="SiteCallNodeKpiSnapshot"/> per originating
|
|
/// node. Nodes with no <c>SiteCalls</c> rows at all are omitted; rows with a
|
|
/// <c>NULL</c> <c>SourceNode</c> are excluded. The stuck cutoff and interval
|
|
/// bounds are interpreted as in <see cref="ComputeKpisAsync"/>.
|
|
/// </summary>
|
|
/// <param name="stuckCutoff">UTC threshold for classifying a row as stuck.</param>
|
|
/// <param name="intervalSince">UTC start of the delivered/failed interval window.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
/// <returns>A task that resolves to a per-node KPI list; nodes with no rows are omitted.</returns>
|
|
Task<IReadOnlyList<SiteCallNodeKpiSnapshot>> ComputePerNodeKpisAsync(
|
|
DateTime stuckCutoff,
|
|
DateTime intervalSince,
|
|
CancellationToken ct = default);
|
|
}
|