89 lines
3.6 KiB
C#
89 lines
3.6 KiB
C#
using ScadaLink.Commons.Types;
|
|
|
|
namespace ScadaLink.Commons.Interfaces;
|
|
|
|
/// <summary>
|
|
/// Site-local source of truth for cached-operation tracking
|
|
/// (<c>ExternalSystem.CachedCall</c> / <c>Database.CachedWrite</c>) — alongside the
|
|
/// Store-and-Forward buffer, this is the row that <c>Tracking.Status(id)</c>
|
|
/// reads (Audit Log #23 / M3). One row per <see cref="TrackedOperationId"/>;
|
|
/// terminal rows are purged after a configurable retention window
|
|
/// (default 7 days).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// The store is intentionally a thin write-API on top of SQLite — not a
|
|
/// dispatcher. Status transitions follow
|
|
/// <c>Submitted → Retrying → Delivered / Parked / Failed / Discarded</c>; rows
|
|
/// in a terminal state never roll back. Implementations must:
|
|
/// <list type="bullet">
|
|
/// <item><description><see cref="RecordEnqueueAsync"/> is insert-if-not-exists
|
|
/// (caller-supplied id is the idempotency key — duplicate enqueues are no-ops).</description></item>
|
|
/// <item><description><see cref="RecordAttemptAsync"/> only updates non-terminal rows.</description></item>
|
|
/// <item><description><see cref="RecordTerminalAsync"/> only flips a non-terminal row to terminal.</description></item>
|
|
/// <item><description><see cref="PurgeTerminalAsync"/> deletes terminal rows whose
|
|
/// <c>TerminalAtUtc</c> is strictly older than the supplied threshold.</description></item>
|
|
/// </list>
|
|
/// </para>
|
|
/// </remarks>
|
|
public interface IOperationTrackingStore
|
|
{
|
|
/// <summary>
|
|
/// Insert a new tracking row in <c>Submitted</c> state with <c>RetryCount = 0</c>.
|
|
/// Idempotent — a duplicate id is silently ignored (the existing row is left
|
|
/// untouched), matching the at-least-once semantics of the calling site
|
|
/// store-and-forward path.
|
|
/// </summary>
|
|
Task RecordEnqueueAsync(
|
|
TrackedOperationId id,
|
|
string kind,
|
|
string? targetSummary,
|
|
string? sourceInstanceId,
|
|
string? sourceScript,
|
|
string? sourceNode,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Advance an in-flight tracking row's status, retry counter, and most-
|
|
/// recent error/HTTP-status. Terminal rows (<see cref="RecordTerminalAsync"/>
|
|
/// already applied) are NOT mutated — the operation has reached its final
|
|
/// outcome and any late-arriving attempt telemetry is dropped on the floor.
|
|
/// </summary>
|
|
Task RecordAttemptAsync(
|
|
TrackedOperationId id,
|
|
string status,
|
|
int retryCount,
|
|
string? lastError,
|
|
int? httpStatus,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Flip a non-terminal tracking row to terminal — sets
|
|
/// <c>TerminalAtUtc = now</c> and writes the final status / error. A row
|
|
/// already in terminal state is left untouched (first-write-wins).
|
|
/// </summary>
|
|
Task RecordTerminalAsync(
|
|
TrackedOperationId id,
|
|
string status,
|
|
string? lastError,
|
|
int? httpStatus,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Return the latest snapshot for the supplied id, or <c>null</c> when no
|
|
/// tracking row exists (purged or never recorded).
|
|
/// </summary>
|
|
Task<TrackingStatusSnapshot?> GetStatusAsync(
|
|
TrackedOperationId id,
|
|
CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Delete terminal rows whose <c>TerminalAtUtc</c> is strictly older than
|
|
/// <paramref name="olderThanUtc"/>. Non-terminal rows are kept regardless
|
|
/// of age (the operation is still in flight).
|
|
/// </summary>
|
|
Task PurgeTerminalAsync(
|
|
DateTime olderThanUtc,
|
|
CancellationToken ct = default);
|
|
}
|