fix(deployment): purge SystemArtifactDeploymentRecords in the terminal-record retention sweep (review 2026-10-21 08/G2)
This commit is contained in:
+11
@@ -194,6 +194,17 @@ public interface IDeploymentManagerRepository
|
||||
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
Task DeleteSystemArtifactDeploymentAsync(int id, CancellationToken cancellationToken = default);
|
||||
/// <summary>
|
||||
/// Deletes system artifact deployment records deployed before <paramref name="cutoffUtc"/>,
|
||||
/// in one bounded batch. One row is written per <i>Deploy Artifacts</i> run and nothing
|
||||
/// reads them back, so they share the terminal deployment-record retention window
|
||||
/// instead of growing without bound.
|
||||
/// </summary>
|
||||
/// <param name="cutoffUtc">Records deployed before this instant are eligible.</param>
|
||||
/// <param name="batchSize">Maximum rows deleted in this call.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used to cancel the operation.</param>
|
||||
/// <returns>The number of rows deleted; fewer than <paramref name="batchSize"/> means the sweep is complete.</returns>
|
||||
Task<int> PurgeSystemArtifactDeploymentRecordsAsync(DateTimeOffset cutoffUtc, int batchSize, CancellationToken cancellationToken = default);
|
||||
|
||||
// DeployedConfigSnapshot
|
||||
/// <summary>
|
||||
|
||||
+23
@@ -285,6 +285,29 @@ public class DeploymentManagerRepository : IDeploymentManagerRepository
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<int> PurgeSystemArtifactDeploymentRecordsAsync(
|
||||
DateTimeOffset cutoffUtc,
|
||||
int batchSize,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Same bounded-batch shape as PurgeTerminalDeploymentRecordsAsync: the caller
|
||||
// re-invokes until fewer than batchSize rows come back. Every row is terminal by
|
||||
// construction (it is written once, after the artifact sweep finished).
|
||||
var stale = await _dbContext.SystemArtifactDeploymentRecords
|
||||
.Where(d => d.DeployedAt < cutoffUtc)
|
||||
.OrderBy(d => d.Id)
|
||||
.Take(batchSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (stale.Count == 0)
|
||||
return 0;
|
||||
|
||||
_dbContext.SystemArtifactDeploymentRecords.RemoveRange(stale);
|
||||
await _dbContext.SaveChangesAsync(cancellationToken);
|
||||
return stale.Count;
|
||||
}
|
||||
|
||||
// --- DeployedConfigSnapshot ---
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -72,6 +72,8 @@ public class DeploymentManagerOptions
|
||||
/// <c>InProgress</c> or <c>Pending</c> row is never purged regardless of age,
|
||||
/// because it is exactly the row the query-before-redeploy reconciliation
|
||||
/// path needs to find. Set to <see cref="TimeSpan.Zero"/> to disable purging.
|
||||
/// The same window bounds system artifact deployment records (one per
|
||||
/// <i>Deploy Artifacts</i> run), purged by their deploy time.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public TimeSpan TerminalDeploymentRecordRetention { get; set; } = TimeSpan.FromDays(365);
|
||||
|
||||
@@ -1330,7 +1330,8 @@ public class DeploymentService
|
||||
instanceId, uniqueName, deploymentId, false, result.Error);
|
||||
|
||||
/// <summary>
|
||||
/// Opportunistic retention sweep for TERMINAL deployment records, rate-limited
|
||||
/// Opportunistic retention sweep for TERMINAL deployment records and system
|
||||
/// artifact deployment records, rate-limited
|
||||
/// to once every <see cref="TerminalPurgeMinInterval"/> per process and bounded
|
||||
/// to <see cref="TerminalPurgeBatchesPerSweep"/> batches per call.
|
||||
///
|
||||
@@ -1379,12 +1380,26 @@ public class DeploymentService
|
||||
break;
|
||||
}
|
||||
|
||||
// System artifact deployment records (one per Deploy Artifacts run) share the
|
||||
// same retention window — nothing reads them back, so without this sweep the
|
||||
// table only ever grows.
|
||||
var artifactPurged = 0;
|
||||
for (var batch = 0; batch < TerminalPurgeBatchesPerSweep; batch++)
|
||||
{
|
||||
var deleted = await _repository.PurgeSystemArtifactDeploymentRecordsAsync(
|
||||
cutoff, TerminalPurgeBatchSize, cancellationToken);
|
||||
artifactPurged += deleted;
|
||||
if (deleted < TerminalPurgeBatchSize)
|
||||
break;
|
||||
}
|
||||
|
||||
purged += artifactPurged;
|
||||
if (purged > 0)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
"Purged {Count} terminal deployment record(s) completed before {Cutoff} " +
|
||||
"(retention {Retention}).",
|
||||
purged, cutoff, retention);
|
||||
"Purged {Count} terminal deployment record(s) ({ArtifactCount} system artifact " +
|
||||
"record(s)) completed before {Cutoff} (retention {Retention}).",
|
||||
purged, artifactPurged, cutoff, retention);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
Reference in New Issue
Block a user