refactor(deployment): injectable terminal-purge rate limiter; test the swallowed failure (ScadaBridge#90)
DeploymentService.TryPurgeTerminalDeploymentRecordsAsync rate-limited its opportunistic retention sweep with a process-wide static tick field, so only one test in the assembly could drive the sweep and its swallow-on-failure path was untested. The limit now lives in TerminalPurgeRateLimiter: a TimeProvider-driven compare-and-swap claim (MinInterval 6 h) registered by AddDeploymentManager as a DI singleton, so every scoped DeploymentService still shares one limit per node. DeploymentService takes it as an optional trailing constructor parameter; a hand-built instance gets its own limiter. The sweep's cutoff now comes from the same clock. Behaviour is otherwise unchanged. Evidence (TerminalPurgeRateLimiterTests): - claim once per interval on an injected clock; 16 concurrent claimants -> exactly one wins; - two services with their own limiters both sweep, two sharing one sweep once; - cutoff = injected now - retention; - a failing artifact batch is logged as a warning with the exception and swallowed, the already-purged terminal rows are still reported, the next call inside the interval does not retry and the first call after it does; a first-batch failure returns 0 and skips the artifact purge; - AddDeploymentManager registers the limiter as a singleton shared across scopes. Mutation-checked: a process-wide static limiter fails 5 tests (incl. the existing artifact-purge test); narrowing the catch fails both failure tests. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -90,8 +90,8 @@ public class DeploymentServiceTests : TestKit
|
||||
/// <summary>
|
||||
/// The retention sweep also purges system artifact deployment records — one per Deploy
|
||||
/// Artifacts run, never read back — with the same cutoff as terminal deployment records.
|
||||
/// NOTE: the sweep is rate-limited by a process-wide static, so this is the only test in
|
||||
/// the assembly that may drive <see cref="DeploymentService.TryPurgeTerminalDeploymentRecordsAsync"/>.
|
||||
/// The rate limiter is per service unless injected (Gitea #90); its behaviour and the sweep's
|
||||
/// swallowed-failure path are covered by <c>TerminalPurgeRateLimiterTests</c>.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user