fix(deploy): persist the artifact deployment record before the best-effort site stamp
Both repositories are scoped over one DbContext, so a failed stamp save left the Site entries tracked as Modified and the deployment record's (uncaught) SaveChangesAsync rethrew it — losing the audit row and failing a deploy in which every site succeeded. Ordering rule now: audit row first, stamp after, inside its own try/catch. Same in RetryForSiteAsync, where the site load is caught too so nothing on the stamp path can reach the method's catch. Also: the method-definitions canonicaliser matches the name property case-insensitively (a naming-policy change at the producer would otherwise silently turn the sort into a no-op), and ComputeCurrentArtifactHashesAsync documents that a per-site query failure aborts the whole batch by design. Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
This commit is contained in:
+14
-3
@@ -354,10 +354,13 @@ public class ArtifactDeploymentServiceTests : TestKit
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeployToAllSitesAsync_StampSaveThrows_DeployStillReportsSuccess()
|
||||
public async Task DeployToAllSitesAsync_StampSaveThrows_DeploymentRecordStillPersistedAndSuccessReported()
|
||||
{
|
||||
// Audit trail beats staleness bookkeeping: the artifacts DID reach the site, so a
|
||||
// failure to record the stamp is logged and swallowed, never reported as a failure.
|
||||
// ORDERING RULE: audit row first, best-effort stamp after. Both repositories are
|
||||
// scoped over ONE DbContext, so a failed stamp save leaves the Site entries tracked
|
||||
// as Modified — stamping first would let that failure rethrow out of the deployment
|
||||
// record's own (uncaught) SaveChangesAsync and lose the audit row for a deploy where
|
||||
// every site succeeded. The record must therefore be saved BEFORE the stamp is tried.
|
||||
var site = new Site("Site One", "site-1") { Id = 1 };
|
||||
_siteRepo.GetAllSitesAsync(Arg.Any<CancellationToken>()).Returns(new List<Site> { site });
|
||||
_siteRepo.SaveChangesAsync(Arg.Any<CancellationToken>())
|
||||
@@ -370,6 +373,14 @@ public class ArtifactDeploymentServiceTests : TestKit
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.Equal(1, result.Value.SuccessCount);
|
||||
await _deploymentRepo.Received(1).AddSystemArtifactDeploymentAsync(
|
||||
Arg.Any<SystemArtifactDeploymentRecord>(), Arg.Any<CancellationToken>());
|
||||
await _deploymentRepo.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
_deploymentRepo.SaveChangesAsync(Arg.Any<CancellationToken>());
|
||||
_siteRepo.UpdateSiteAsync(site, Arg.Any<CancellationToken>());
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user