feat(deploy): pending-deployment repository with supersession + purge

This commit is contained in:
Joseph Doherty
2026-06-26 12:19:54 -04:00
parent 81cb455f19
commit 290acfb1f0
3 changed files with 276 additions and 0 deletions
@@ -197,6 +197,60 @@ public class DeploymentManagerRepository : IDeploymentManagerRepository
}
}
// --- Notify-and-fetch: PendingDeployment staging store ---
/// <inheritdoc />
public async Task AddPendingDeploymentAsync(PendingDeployment pending, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(pending);
// Supersession: a newer deploy for the same instance replaces any prior pending
// row. Safe because the per-instance operation lock serializes same-instance
// deploys. SaveChanges is deferred to the caller, matching the other Add methods.
var prior = await _dbContext.Set<PendingDeployment>()
.Where(p => p.InstanceId == pending.InstanceId)
.ToListAsync(cancellationToken);
if (prior.Count > 0)
{
_dbContext.Set<PendingDeployment>().RemoveRange(prior);
}
await _dbContext.Set<PendingDeployment>().AddAsync(pending, cancellationToken);
}
/// <inheritdoc />
public Task<PendingDeployment?> GetPendingDeploymentByIdAsync(string deploymentId, CancellationToken cancellationToken = default)
{
return _dbContext.Set<PendingDeployment>()
.FirstOrDefaultAsync(p => p.DeploymentId == deploymentId, cancellationToken);
}
/// <inheritdoc />
public async Task DeletePendingDeploymentByIdAsync(string deploymentId, CancellationToken cancellationToken = default)
{
var row = await _dbContext.Set<PendingDeployment>()
.FirstOrDefaultAsync(p => p.DeploymentId == deploymentId, cancellationToken);
if (row != null)
{
_dbContext.Set<PendingDeployment>().Remove(row);
}
}
/// <inheritdoc />
public async Task<int> PurgeExpiredPendingDeploymentsAsync(DateTimeOffset nowUtc, CancellationToken cancellationToken = default)
{
// Self-contained TTL maintenance op: commits its own delete and returns the count.
var expired = await _dbContext.Set<PendingDeployment>()
.Where(p => p.ExpiresAtUtc <= nowUtc)
.ToListAsync(cancellationToken);
if (expired.Count == 0)
{
return 0;
}
_dbContext.Set<PendingDeployment>().RemoveRange(expired);
await _dbContext.SaveChangesAsync(cancellationToken);
return expired.Count;
}
// --- Instance lookups for deployment pipeline ---
/// <inheritdoc />