fix(auditlog): page the site audit purge, bound incremental_vacuum per page, fail fast instead of parking writers on a full queue (review 2026-10-21 06/MEM-1)

This commit is contained in:
Joseph Doherty
2026-10-22 06:23:35 -04:00
parent 268b55e350
commit 1da5d0bac4
6 changed files with 261 additions and 56 deletions
@@ -29,8 +29,11 @@ public sealed class SqliteAuditWriterOptions
/// <summary>
/// Capacity of the bounded write queue. Set high enough that ordinary
/// script bursts never fill it; <see cref="System.Threading.Channels.BoundedChannelFullMode.Wait"/>
/// applies when the writer falls behind.
/// script bursts never fill it. When the writer falls behind and the queue is
/// full, <c>WriteAsync</c> fails fast with <see cref="SqliteAuditWriterSaturatedException"/>
/// instead of parking an unbounded number of waiters (review 2026-10-21 06/MEM-1);
/// <see cref="FallbackAuditWriter"/> turns that into its documented best-effort
/// drop-oldest ring + <c>SiteAuditWriteFailures</c> counter bump.
/// </summary>
public int ChannelCapacity { get; set; } = 4096;
@@ -40,6 +43,23 @@ public sealed class SqliteAuditWriterOptions
/// <summary>Soft flush interval the writer enforces when fewer than BatchSize events are queued.</summary>
public int FlushIntervalMs { get; set; } = 50;
/// <summary>
/// Maximum rows the retention purge deletes in ONE transaction. The purge loops page by
/// page and releases the write lock between pages, so the batched hot-path writer
/// interleaves with a large purge instead of stalling behind one multi-minute DELETE
/// (review 2026-10-21 06/MEM-1 — the same hazard class register row 34 fixed for
/// <c>site_events</c>).
/// </summary>
public int PurgeBatchSize { get; set; } = 5000;
/// <summary>
/// Free pages reclaimed by the bounded <c>PRAGMA incremental_vacuum(N)</c> run after each
/// purge page. Bounds the time the vacuum holds the write lock; pages not reclaimed in
/// one step stay on the freelist and are reused by later inserts or reclaimed by the
/// next purge.
/// </summary>
public int PurgeVacuumPagesPerBatch { get; set; } = 1000;
/// <summary>
/// Poll cadence, in seconds, for the <c>SiteAuditBacklogReporter</c> hosted service
/// that probes the SQLite audit backlog and pushes the snapshot onto the site health