fix(reconcile): heal all concurrently-missing nodes — return existing pending token instead of omitting

This commit is contained in:
Joseph Doherty
2026-06-26 17:09:42 -04:00
parent 99254b71de
commit 6538216b0c
5 changed files with 145 additions and 13 deletions
@@ -159,6 +159,36 @@ public class PendingDeploymentRepositoryTests : IDisposable
Assert.Null(await _repository.GetPendingDeploymentByIdAsync("does-not-exist"));
}
[Fact]
public async Task GetPendingDeploymentByInstanceId_ReturnsRow_WhenPresent()
{
// Startup-reconcile read path: when StagePendingIfAbsent reports a row already exists
// (concurrent reconcile from the other node, or an in-flight deploy), the handler reads
// the existing row by instance id to hand the second node the same fetch token.
var instanceId = await SeedInstanceAsync("Inst9");
await _repository.AddPendingDeploymentAsync(NewPending("dep9", instanceId, "{\"v\":9}"));
await _repository.SaveChangesAsync();
var row = await _repository.GetPendingDeploymentByInstanceIdAsync(instanceId);
Assert.NotNull(row);
Assert.Equal("dep9", row!.DeploymentId);
Assert.Equal(instanceId, row.InstanceId);
Assert.Equal("tok-dep9", row.Token);
Assert.Equal("{\"v\":9}", row.ConfigurationJson);
}
[Fact]
public async Task GetPendingDeploymentByInstanceId_ReturnsNull_WhenAbsent()
{
// No pending row staged for this instance → null (the reconcile fallback/omit path).
var instanceId = await SeedInstanceAsync("Inst10");
var row = await _repository.GetPendingDeploymentByInstanceIdAsync(instanceId);
Assert.Null(row);
}
[Fact]
public async Task AddPendingDeployment_MultiplePriorRowsSameInstance_AllSuperseded()
{