140 lines
8.1 KiB
C#
140 lines
8.1 KiB
C#
using ZB.MOM.WW.Audit;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
|
|
|
/// <summary>
|
|
/// Site-local audit-log queue surface consumed by the site
|
|
/// <c>SiteAuditTelemetryActor</c> drain loop and the M6
|
|
/// <c>SiteStreamGrpcServer.PullAuditEvents</c> reconciliation handler.
|
|
/// Extracted from <c>SqliteAuditWriter</c> so both consumers can be
|
|
/// unit-tested against a stub without touching SQLite; the
|
|
/// <c>SqliteAuditWriter</c> production type implements this interface
|
|
/// and DI wires the same singleton instance to every consumer.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Lives in Commons (rather than alongside <c>SqliteAuditWriter</c> in
|
|
/// <c>ZB.MOM.WW.ScadaBridge.AuditLog</c>) because <c>ZB.MOM.WW.ScadaBridge.Communication</c> — which
|
|
/// hosts the M6 gRPC pull handler — must depend on this interface and
|
|
/// <c>ZB.MOM.WW.ScadaBridge.AuditLog</c> already depends on <c>ZB.MOM.WW.ScadaBridge.Communication</c>.
|
|
/// Pulling the interface up to Commons breaks the would-be cycle while
|
|
/// keeping the implementation in the AuditLog component.
|
|
///
|
|
/// Only the methods the drain and pull paths need are exposed — the
|
|
/// hot-path <c>WriteAsync</c> stays on <see cref="IAuditWriter"/>
|
|
/// (script-thread surface), separated by concern so each side can be
|
|
/// mocked independently.
|
|
/// </remarks>
|
|
public interface ISiteAuditQueue
|
|
{
|
|
/// <summary>
|
|
/// Returns up to <paramref name="limit"/> rows currently in
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Pending"/>,
|
|
/// oldest first. Idempotent — repeated calls before
|
|
/// <see cref="MarkForwardedAsync"/> will yield the same rows again.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// AuditLog-001: cached-lifecycle audit kinds
|
|
/// (<see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.CachedSubmit"/>,
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.ApiCallCached"/>,
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.DbWriteCached"/>,
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.CachedResolve"/>) are
|
|
/// EXCLUDED from this result — they ride the combined-telemetry drain via
|
|
/// <see cref="ReadPendingCachedTelemetryAsync"/> + the central
|
|
/// <c>OnCachedTelemetryAsync</c> dual-write transaction. The audit-only
|
|
/// drain handled by this method covers everything else (sync ApiCall /
|
|
/// DbWrite, NotifySend, InboundRequest, etc.).
|
|
/// </remarks>
|
|
/// <param name="limit">Maximum number of rows to return.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
Task<IReadOnlyList<AuditEvent>> ReadPendingAsync(int limit, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// AuditLog-001: returns up to <paramref name="limit"/> rows in
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Pending"/>
|
|
/// whose audit kind belongs to the cached-call lifecycle
|
|
/// vocabulary (<see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.CachedSubmit"/>,
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.ApiCallCached"/>,
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.DbWriteCached"/>,
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditKind.CachedResolve"/>),
|
|
/// oldest first. The site-side <c>SiteAuditTelemetryActor</c> drains these
|
|
/// rows separately, joining each with the matching operational tracking row
|
|
/// (<c>IOperationTrackingStore.GetStatusAsync</c>) before pushing the
|
|
/// combined <c>CachedTelemetryBatch</c> via
|
|
/// <c>ISiteStreamAuditClient.IngestCachedTelemetryAsync</c>. Idempotent —
|
|
/// repeated calls before <see cref="MarkForwardedAsync"/> yield the same
|
|
/// rows again.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The two-drain partition is the production wiring of the combined-telemetry
|
|
/// transport specified in Component-AuditLog.md §"Cached Operations —
|
|
/// Combined Telemetry": cached rows MUST flow with their matching
|
|
/// <c>SiteCalls</c> upsert through one MS SQL transaction at central. The
|
|
/// pre-AuditLog-001 implementation drained cached rows through the
|
|
/// audit-only path, leaving the operational half unsent and the central
|
|
/// dual-write handler unreachable. Returning them via this dedicated read
|
|
/// surface lets the new drain join with the tracking store before push.
|
|
/// </remarks>
|
|
/// <param name="limit">Maximum number of rows to return.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
Task<IReadOnlyList<AuditEvent>> ReadPendingCachedTelemetryAsync(int limit, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Flips the supplied EventIds from
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Pending"/> to
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Forwarded"/>.
|
|
/// Non-existent or already-forwarded ids are silent no-ops.
|
|
/// </summary>
|
|
/// <param name="eventIds">Event IDs to mark as forwarded.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
Task MarkForwardedAsync(IReadOnlyList<Guid> eventIds, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// M6 reconciliation-pull read surface: returns up to <paramref name="batchSize"/>
|
|
/// rows whose <see cref="AuditEvent.OccurredAtUtc"/> >= <paramref name="sinceUtc"/>
|
|
/// and whose <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState"/> is still
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Pending"/> or
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Forwarded"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Rows in the brief race window between site-Forwarded and central-ingest are
|
|
/// intentionally included: the central reconciliation puller dedups on
|
|
/// <see cref="AuditEvent.EventId"/>, so re-shipping is safe and avoids losing rows
|
|
/// whose telemetry ack was acted on locally but never landed centrally. Ordering
|
|
/// is oldest <see cref="AuditEvent.OccurredAtUtc"/> first with
|
|
/// <see cref="AuditEvent.EventId"/> as the deterministic tiebreaker.
|
|
/// </remarks>
|
|
/// <param name="sinceUtc">Lower bound timestamp (UTC).</param>
|
|
/// <param name="batchSize">Maximum number of rows to return.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
Task<IReadOnlyList<AuditEvent>> ReadPendingSinceAsync(
|
|
DateTime sinceUtc, int batchSize, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// M6 reconciliation-pull commit surface: flips the supplied EventIds to
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Reconciled"/>,
|
|
/// but ONLY for rows currently in
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Pending"/> or
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Forwarded"/>.
|
|
/// Rows already in <see cref="ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AuditForwardState.Reconciled"/>
|
|
/// are left untouched (idempotent re-call). Non-existent ids are silent no-ops.
|
|
/// </summary>
|
|
/// <param name="eventIds">Event IDs to mark as reconciled.</param>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
Task MarkReconciledAsync(IReadOnlyList<Guid> eventIds, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// M6 Bundle E (T6) health-metric surface: returns a point-in-time snapshot
|
|
/// of the site queue's pending count + oldest pending timestamp + on-disk
|
|
/// SQLite file size. Surfaced on
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Messages.Health.SiteHealthReport"/> as
|
|
/// <c>SiteAuditBacklog</c> by the periodic <c>SiteAuditBacklogReporter</c>
|
|
/// hosted service so a stuck site→central drain is visible on the central
|
|
/// health dashboard. Safe to call concurrently with hot-path writes —
|
|
/// implementations are expected to take the same connection lock used by
|
|
/// the hot-path INSERT batch and the drain queries.
|
|
/// </summary>
|
|
/// <param name="ct">Cancellation token.</param>
|
|
Task<SiteAuditBacklogSnapshot> GetBacklogStatsAsync(CancellationToken ct = default);
|
|
}
|