ff8766ec8b
Adds the IAuditWriter composer that sits between the script-side ScriptRuntimeContext audit emission (Bundle F) and the primary SqliteAuditWriter. Honours the alog.md §7 guarantee that audit-write failures NEVER abort the user-facing action: - Primary throw -> log Warning, increment IAuditWriteFailureCounter (Bundle G's health-metric sink), stash the event in the drop-oldest RingBufferFallback, return success to the caller. - Primary success -> opportunistically drain the ring back through the primary in FIFO order, behind the triggering event. Drain is serialised via a SemaphoreSlim gate so concurrent recoveries don't double-replay; a drain-side re-throw re-enqueues at the tail and breaks out (the next successful write retries). Adds IAuditWriteFailureCounter as the lightweight DI seam (one void Increment()), and a TryDequeue helper on RingBufferFallback that the recovery path uses to pop one item without blocking. Tests (4 new, total 26 -> 30): - WriteAsync_PrimaryThrows_EventLandsInRing_CallReturnsSuccess - WriteAsync_PrimaryRecovers_RingDrains_InFIFOOrder_OnNextWrite (order: trigger first, then ring backlog in submission FIFO) - WriteAsync_PrimaryAlwaysSucceeds_Ring_StaysEmpty - WriteAsync_FailureCounter_Incremented_Per_PrimaryFailure
15 lines
542 B
C#
15 lines
542 B
C#
namespace ScadaLink.AuditLog.Site;
|
|
|
|
/// <summary>
|
|
/// Lightweight counter sink invoked by <see cref="FallbackAuditWriter"/> every
|
|
/// time the primary <see cref="SqliteAuditWriter"/> throws on an audit write.
|
|
/// Bundle G (M2-T11) implements this as a thread-safe Interlocked counter
|
|
/// bridged into the Site Health Monitoring report payload as
|
|
/// <c>SiteAuditWriteFailures</c>.
|
|
/// </summary>
|
|
public interface IAuditWriteFailureCounter
|
|
{
|
|
/// <summary>Increment the audit-write failure counter by one.</summary>
|
|
void Increment();
|
|
}
|