test: verify scheduler CAS on PostgreSQL (AEG-V15-036)

Adds a lease-loss/reacquire integration rehearsal and fixes Dapper due-schedule materialization with an explicit row DTO. Evidence: PostgreSQL test 1/1 passed; TRX SHA256 49627FF0180034D2A7A1E4393448C73D337D918E7CE47EA9FC2BDB144FBBA833.
This commit is contained in:
2026-08-09 02:11:23 +09:00
parent 5a1570790c
commit 00957bf384
6 changed files with 147 additions and 5 deletions
@@ -79,8 +79,20 @@ public sealed class DapperModelScheduleRepository(IDbConnectionFactory connectio
public async Task<IReadOnlyList<DueModelOperation>> AcquireDueAsync(DateTimeOffset now, string leaseOwner, TimeSpan leaseDuration, int limit, CancellationToken cancellationToken)
{
await using var connection = await connectionFactory.OpenAsync(cancellationToken);
var items = await connection.QueryAsync<DueModelOperation>(new CommandDefinition(AcquireSql, new { Now = now, LeaseOwner = leaseOwner, LeaseUntil = now.Add(leaseDuration), Limit = limit }, cancellationToken: cancellationToken));
return items.AsList();
var rows = await connection.QueryAsync<DueScheduleRow>(new CommandDefinition(AcquireSql, new { Now = now, LeaseOwner = leaseOwner, LeaseUntil = now.Add(leaseDuration), Limit = limit }, cancellationToken: cancellationToken));
return rows.Select(row => new DueModelOperation(
row.ScheduleId,
row.OperationCode,
row.ScopeKey,
row.Cadence,
row.AutomationMode,
row.Queue,
row.IdempotencyKey,
row.ScheduleVersion,
row.DispatchRevision,
row.ScheduledFor,
row.CatchUpPolicy,
row.MaxCatchUp)).ToArray();
}
public async Task MarkDispatchedAsync(Guid scheduleId, string leaseOwner, int expectedDispatchRevision, string backgroundJobId, DateTimeOffset dispatchedAt, DateTimeOffset nextDueAt, CancellationToken cancellationToken)
@@ -102,4 +114,20 @@ public sealed class DapperModelScheduleRepository(IDbConnectionFactory connectio
await using var connection = await connectionFactory.OpenAsync(cancellationToken);
await connection.ExecuteAsync(new CommandDefinition(ReleaseSql, new { ScheduleId = scheduleId, LeaseOwner = leaseOwner, ExpectedDispatchRevision = expectedDispatchRevision, ReasonCode = reasonCode, ReleasedAt = releasedAt }, cancellationToken: cancellationToken));
}
private sealed class DueScheduleRow
{
public Guid ScheduleId { get; init; }
public string OperationCode { get; init; } = string.Empty;
public string ScopeKey { get; init; } = string.Empty;
public string Cadence { get; init; } = string.Empty;
public string AutomationMode { get; init; } = string.Empty;
public string Queue { get; init; } = string.Empty;
public string IdempotencyKey { get; init; } = string.Empty;
public int ScheduleVersion { get; init; }
public int DispatchRevision { get; init; }
public DateTimeOffset ScheduledFor { get; init; }
public string CatchUpPolicy { get; init; } = string.Empty;
public int MaxCatchUp { get; init; }
}
}