feat(comms): site-side PullAuditEvents handler (#23 M6)
This commit is contained in:
73
src/ScadaLink.Commons/Interfaces/Services/ISiteAuditQueue.cs
Normal file
73
src/ScadaLink.Commons/Interfaces/Services/ISiteAuditQueue.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using ScadaLink.Commons.Entities.Audit;
|
||||
|
||||
namespace ScadaLink.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>ScadaLink.AuditLog</c>) because <c>ScadaLink.Communication</c> — which
|
||||
/// hosts the M6 gRPC pull handler — must depend on this interface and
|
||||
/// <c>ScadaLink.AuditLog</c> already depends on <c>ScadaLink.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="ScadaLink.Commons.Types.Enums.AuditForwardState.Pending"/>,
|
||||
/// oldest first. Idempotent — repeated calls before
|
||||
/// <see cref="MarkForwardedAsync"/> will yield the same rows again.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<AuditEvent>> ReadPendingAsync(int limit, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Flips the supplied EventIds from
|
||||
/// <see cref="ScadaLink.Commons.Types.Enums.AuditForwardState.Pending"/> to
|
||||
/// <see cref="ScadaLink.Commons.Types.Enums.AuditForwardState.Forwarded"/>.
|
||||
/// Non-existent or already-forwarded ids are silent no-ops.
|
||||
/// </summary>
|
||||
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="ScadaLink.Commons.Types.Enums.AuditForwardState"/> is still
|
||||
/// <see cref="ScadaLink.Commons.Types.Enums.AuditForwardState.Pending"/> or
|
||||
/// <see cref="ScadaLink.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>
|
||||
Task<IReadOnlyList<AuditEvent>> ReadPendingSinceAsync(
|
||||
DateTime sinceUtc, int batchSize, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// M6 reconciliation-pull commit surface: flips the supplied EventIds to
|
||||
/// <see cref="ScadaLink.Commons.Types.Enums.AuditForwardState.Reconciled"/>,
|
||||
/// but ONLY for rows currently in
|
||||
/// <see cref="ScadaLink.Commons.Types.Enums.AuditForwardState.Pending"/> or
|
||||
/// <see cref="ScadaLink.Commons.Types.Enums.AuditForwardState.Forwarded"/>.
|
||||
/// Rows already in <see cref="ScadaLink.Commons.Types.Enums.AuditForwardState.Reconciled"/>
|
||||
/// are left untouched (idempotent re-call). Non-existent ids are silent no-ops.
|
||||
/// </summary>
|
||||
Task MarkReconciledAsync(IReadOnlyList<Guid> eventIds, CancellationToken ct = default);
|
||||
}
|
||||
Reference in New Issue
Block a user