using System.Threading.Channels; using ROLAC.API.Entities.Logging; namespace ROLAC.API.Services.Logging; /// /// A singleton, bounded in-memory queue decoupling log producers (the ILogger hot path, the /// audit interceptor, singleton services) from the single background DB writer. Enqueue is a /// non-blocking TryWrite; when full the OLDEST entry is dropped (DropWrite) rather than /// blocking a request thread or throwing — logging must never throw or stall business code. /// Carries both SystemLog and AuditLog rows via a small union envelope. /// public sealed class SystemLogQueue { private readonly Channel _channel = Channel.CreateBounded(new BoundedChannelOptions(capacity: 4096) { FullMode = BoundedChannelFullMode.DropWrite, SingleReader = true, SingleWriter = false, }); public bool TryEnqueue(SystemLog log) => _channel.Writer.TryWrite(new LogEnvelope(log, null)); public bool TryEnqueue(AuditLog log) => _channel.Writer.TryWrite(new LogEnvelope(null, log)); public IAsyncEnumerable ReadAllAsync(CancellationToken cancellationToken) => _channel.Reader.ReadAllAsync(cancellationToken); } /// Either a SystemLog or an AuditLog — exactly one is non-null. public sealed record LogEnvelope(SystemLog? System, AuditLog? Audit);