feat(audit): M5.5 per-channel retention overrides via purge-role bounded delete (T3)
This commit is contained in:
@@ -37,6 +37,33 @@ public sealed class AuditLogOptions
|
||||
/// <summary>Central retention window in days (default 365, range [30, 3650]).</summary>
|
||||
public int RetentionDays { get; set; } = 365;
|
||||
|
||||
/// <summary>
|
||||
/// M5.5 (T3) per-channel retention overrides, keyed by the canonical channel name
|
||||
/// (the <see cref="AuditChannel"/> enum name — e.g. <c>ApiOutbound</c>,
|
||||
/// <c>DbOutbound</c>, <c>Notification</c>, <c>ApiInbound</c>). The value is a
|
||||
/// retention window in days that MUST be SHORTER than or equal to the global
|
||||
/// <see cref="RetentionDays"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The global <see cref="RetentionDays"/> window is enforced by month-partition
|
||||
/// switch-out, which is channel-blind: it can only drop a whole month once every
|
||||
/// row in it is older than the global window. A per-channel override therefore
|
||||
/// can only ever expire rows EARLIER than the global purge would — never later
|
||||
/// (a longer per-channel window is meaningless because the partition switch-out
|
||||
/// would already have dropped the month). Overrides shorter than the global window
|
||||
/// are honoured by the purge actor as a bounded, batched row DELETE on the
|
||||
/// maintenance path (see <c>AuditLogPurgeActor</c>); the append-only writer/ingest
|
||||
/// role is unaffected.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Each value is validated to be in <c>[30, RetentionDays]</c> by
|
||||
/// <c>AuditLogOptionsValidator</c>; keys that are not recognized
|
||||
/// <see cref="AuditChannel"/> names are rejected.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Dictionary<string, int> PerChannelRetentionDays { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Per-body byte ceiling applied to <see cref="AuditEvent.RequestSummary"/> and
|
||||
/// <see cref="AuditEvent.ResponseSummary"/> for <see cref="AuditChannel.ApiInbound"/> rows
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ZB.MOM.WW.Configuration;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Configuration;
|
||||
|
||||
@@ -52,5 +53,27 @@ public sealed class AuditLogOptionsValidator : OptionsValidatorBase<AuditLogOpti
|
||||
!(options.InboundMaxBytes < MinInboundMaxBytes || options.InboundMaxBytes > MaxInboundMaxBytes),
|
||||
$"AuditLog:{nameof(AuditLogOptions.InboundMaxBytes)} ({options.InboundMaxBytes}) " +
|
||||
$"must be in [{MinInboundMaxBytes}, {MaxInboundMaxBytes}] bytes.");
|
||||
|
||||
// M5.5 (T3): per-channel retention overrides. Each entry must be keyed by a
|
||||
// recognized AuditChannel name and carry a window in [MinRetentionDays,
|
||||
// RetentionDays] — i.e. SHORTER than or equal to the global window. A longer
|
||||
// per-channel window is meaningless under month-partition switch-out (governed
|
||||
// by the global window), so it is rejected rather than silently ignored.
|
||||
foreach (var (channelKey, days) in options.PerChannelRetentionDays)
|
||||
{
|
||||
builder.RequireThat(
|
||||
Enum.TryParse<AuditChannel>(channelKey, ignoreCase: false, out _),
|
||||
$"AuditLog:{nameof(AuditLogOptions.PerChannelRetentionDays)} key '{channelKey}' " +
|
||||
$"is not a recognized channel name. Valid keys: {string.Join(", ", Enum.GetNames<AuditChannel>())}.");
|
||||
|
||||
// Valid when days is within [MinRetentionDays, RetentionDays] inclusive.
|
||||
// The lower bound matches the global RetentionDays floor; the upper bound
|
||||
// is the configured global window (longer is meaningless — see remarks).
|
||||
builder.RequireThat(
|
||||
!(days < MinRetentionDays || days > options.RetentionDays),
|
||||
$"AuditLog:{nameof(AuditLogOptions.PerChannelRetentionDays)}['{channelKey}'] ({days}) " +
|
||||
$"must be in [{MinRetentionDays}, {nameof(AuditLogOptions.RetentionDays)}={options.RetentionDays}] days " +
|
||||
"— a per-channel window must be shorter than or equal to the global retention window.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user