0ffd4bdbea
Comment/XML-doc changes only, no code logic: - strip project-tracking references (WP*, P*-*, row-NN, #NN, Task N) from comments, keeping the explanatory rationale - add missing summaries, <param>, <returns>, <typeparam> and <inheritdoc/> - replace misused <inheritdoc/> with real docs; where <inheritdoc/> was combined with useful remarks, move the rationale into // comments - drop stale replicationActor <param> on DeploymentManagerActor ctor Remaining 5 are false positives (CWE-1236 x2, failures-1, year-0001, M365). Build 0 errors / 0 warnings.
129 lines
6.5 KiB
C#
129 lines
6.5 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Central;
|
|
|
|
/// <summary>
|
|
/// Tuning knobs for the central <see cref="AuditLogPurgeActor"/> singleton.
|
|
/// Default cadence is 24 hours; the retention window itself
|
|
/// is sourced from <see cref="ZB.MOM.WW.ScadaBridge.AuditLog.Configuration.AuditLogOptions.RetentionDays"/>
|
|
/// (default 365) so operators tune retention from a single section.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// The purge actor is a daily-cadence singleton, not a hot-loop. The
|
|
/// partition switch itself is metadata-only (since the
|
|
/// <c>AlignAuditLogEventIdUniqueness</c> migration it no longer drops and rebuilds a
|
|
/// non-aligned unique index around it), but it still takes schema-modification
|
|
/// locks and competes with ingest for the same table. Lower this only when an
|
|
/// operator can prove they need sub-daily purge granularity.
|
|
/// </para>
|
|
/// <para>
|
|
/// <see cref="IntervalOverride"/> exists for tests to drop the cadence to
|
|
/// milliseconds; production config is expected to set <see cref="IntervalHours"/>
|
|
/// only. Because this options class is <c>Bind</c>-ed wholesale, a config value
|
|
/// at <c>AuditLog:Purge:IntervalOverride</c> would bind if present (and would
|
|
/// bypass the <see cref="Interval"/> minimum clamp) — operators must not set it.
|
|
/// </para>
|
|
/// </remarks>
|
|
public sealed class AuditLogPurgeOptions
|
|
{
|
|
/// <summary>Period of the purge tick in hours (default 24).</summary>
|
|
public int IntervalHours { get; set; } = 24;
|
|
|
|
/// <summary>Maximum rows deleted for each channel in one purge tick (default 50,000); remaining backlog resumes on later ticks.</summary>
|
|
public int MaxPurgedRowsPerChannelPerTick { get; set; } = 50_000;
|
|
|
|
/// <summary>
|
|
/// Batch size for the per-channel retention-override row DELETE
|
|
/// (<see cref="ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories.IAuditLogRepository.PurgeChannelOlderThanAsync"/>).
|
|
/// Each <c>DELETE TOP (@batch)</c> caps the transaction-log and lock footprint
|
|
/// per statement; the repository stops at <see cref="MaxPurgedRowsPerChannelPerTick"/>
|
|
/// so a backlogged channel yields to later channels. Default 5000 keeps individual
|
|
/// deletes short on a busy central DB. Clamped to a sane minimum in
|
|
/// <see cref="ChannelPurgeBatchSize"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The operator-facing config key is <c>ChannelPurgeBatchSize</c>
|
|
/// (per Component-AuditLog.md), so the binder maps that documented key onto this
|
|
/// backing property via <see cref="ConfigurationKeyNameAttribute"/>. The unattributed
|
|
/// property name (<c>ChannelPurgeBatchSizeConfigured</c>) would otherwise have been
|
|
/// the bind key, silently ignoring the documented section.
|
|
/// </remarks>
|
|
[ConfigurationKeyName("ChannelPurgeBatchSize")]
|
|
public int ChannelPurgeBatchSizeConfigured { get; set; } = 5000;
|
|
|
|
/// <summary>
|
|
/// Resolves the effective per-channel purge batch size, clamped to at least 1 so
|
|
/// a misconfigured <c>0</c>/negative value cannot make the repository's DELETE
|
|
/// loop spin or throw.
|
|
/// </summary>
|
|
public int ChannelPurgeBatchSize => ChannelPurgeBatchSizeConfigured < 1 ? 1 : ChannelPurgeBatchSizeConfigured;
|
|
|
|
/// <summary>
|
|
/// Per-command timeout (in minutes) for the maintenance SQL the purge tick issues —
|
|
/// both the partition switch-out staging batch
|
|
/// (<see cref="ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories.IAuditLogRepository.SwitchOutPartitionAsync"/>)
|
|
/// and each per-channel <c>DELETE TOP</c> batch. Default 30 minutes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The ADO.NET default command timeout is ~30 seconds. On a large or contended partition the
|
|
/// SWITCH batch can exceed that and abort mid-flight, leaving an orphaned staging table for the
|
|
/// next tick's CATCH branch to clean up (arch-review 04, S2). A generous maintenance timeout
|
|
/// lets the metadata-only switch complete rather than self-locking. Resolved via
|
|
/// <see cref="ResolvedMaintenanceCommandTimeout"/>, clamped to a 1-minute floor.
|
|
/// </remarks>
|
|
public int MaintenanceCommandTimeoutMinutes { get; set; } = 30;
|
|
|
|
/// <summary>
|
|
/// Resolves the effective maintenance command timeout, clamped to at least 1 minute so a
|
|
/// misconfigured <c>0</c>/negative value cannot yield a zero/negative timeout (which ADO.NET
|
|
/// interprets as "no timeout" for <c>0</c> and rejects for negatives).
|
|
/// </summary>
|
|
public TimeSpan ResolvedMaintenanceCommandTimeout =>
|
|
TimeSpan.FromMinutes(MaintenanceCommandTimeoutMinutes < 1 ? 1 : MaintenanceCommandTimeoutMinutes);
|
|
|
|
/// <summary>
|
|
/// Test-only override for finer control over the tick cadence than
|
|
/// whole-hour resolution allows. When non-null, takes precedence over
|
|
/// <see cref="IntervalHours"/> AND bypasses the <see cref="Interval"/>
|
|
/// minimum clamp (so tests can use millisecond cadences). Production
|
|
/// config exposes <see cref="IntervalHours"/> only and never sets this
|
|
/// knob — but because the options class is <c>Bind</c>-ed wholesale, a
|
|
/// config value at <c>AuditLog:Purge:IntervalOverride</c> WOULD bind if
|
|
/// present; operators must not set it.
|
|
/// </summary>
|
|
public TimeSpan? IntervalOverride { get; set; }
|
|
|
|
/// <summary>
|
|
/// Minimum interval the config-bound <see cref="IntervalHours"/> can
|
|
/// resolve to. Clamps a misconfigured <c>IntervalHours: 0</c> (or a
|
|
/// negative value) away from <see cref="TimeSpan.Zero"/> — a zero
|
|
/// interval would make Akka's <c>ScheduleTellRepeatedlyCancelable</c>
|
|
/// spin, looping the partition drop/rebuild dance into a sustained SQL
|
|
/// outage. The test-only <see cref="IntervalOverride"/> bypasses this
|
|
/// clamp so unit tests can still drop the cadence to milliseconds.
|
|
/// </summary>
|
|
private static readonly TimeSpan MinConfiguredInterval = TimeSpan.FromMinutes(1);
|
|
|
|
/// <summary>
|
|
/// Resolves the effective tick interval, honouring the test override
|
|
/// when set. Falls back to <see cref="IntervalHours"/>, clamped to at
|
|
/// least <see cref="MinConfiguredInterval"/> so a zero/negative config
|
|
/// value can never yield <see cref="TimeSpan.Zero"/> (which would spin
|
|
/// the scheduler).
|
|
/// </summary>
|
|
public TimeSpan Interval
|
|
{
|
|
get
|
|
{
|
|
if (IntervalOverride is { } overrideValue)
|
|
{
|
|
return overrideValue;
|
|
}
|
|
|
|
var resolved = TimeSpan.FromHours(IntervalHours);
|
|
return resolved < MinConfiguredInterval ? MinConfiguredInterval : resolved;
|
|
}
|
|
}
|
|
}
|