ITraxAuditSink

NO WARRANTY. Trax auth is plumbing, not a security product. You are solely responsible for securing systems that use it. See API Security.

Destination for audit entries. Hosts implement once per deployment (Postgres, Serilog, CloudWatch, S3, whatever).

Signature

public interface ITraxAuditSink
{
    Task WriteAsync(IReadOnlyList<TraxAuditEntry> batch, CancellationToken ct);
}

Guarantees

  • Called from the background writer thread, never from the request thread.
  • Batch size ranges from 1 to TraxAuditOptions.BatchSize.
  • Exceptions are retried up to MaxRetries times with exponential backoff. After that the batch is dropped, logged, and counted in trax.audit.dropped.
  • ct is not cancelled when shutdown begins: the writer keeps writing accepted entries until the host's shutdown timeout, and ct fires then. Observe it, so a write that cannot finish gives up promptly; whatever was unwritten is counted as dropped either way.
  • Writer swallows all failures. A crashed sink must not crash GraphQL requests.

Example

Postgres sink with IDbContextFactory:

public sealed class PostgresAuditSink(IDbContextFactory<AppDbContext> factory) : ITraxAuditSink
{
    public async Task WriteAsync(IReadOnlyList<TraxAuditEntry> batch, CancellationToken ct)
    {
        await using var db = await factory.CreateDbContextAsync(ct);
        db.AuditEntries.AddRange(batch.Select(e => new AuditRow(e)));
        await db.SaveChangesAsync(ct);
    }
}