fix(adm-008): correcciones del verify loop
Seis ajustes post-verify detectados durante la corrida full de tests: 1. PuntoDeVentaRepository: UQ_PuntoDeVenta_Medio_AFIP (no _MedioId_NumeroAFIP) — el catch de unique violation no disparaba → 500 en race duplicado. 2. Application.DependencyInjection: registro de 8 handlers PuntosDeVenta — sin esto, dispatcher arrojaba "No service registered" → 500. 3. ReservarNumeroCommandHandler: backoff ampliado a 5 retries [25, 75, 200, 500, 1200]ms para soportar 50 threads concurrentes. 4. SecuenciaComprobante: SYSTEM_VERSIONING = OFF (AD8 revisitado). Under UPDATE concurrente sobre misma fila, el engine arroja "transaction time earlier than period start time" — limitación conocida de Temporal Tables con alta contención de UPDATEs. Decisión: secuencia es operacional, no configuración → sin history. V013 y SqlTestFixture actualizados para ser idempotentes. 5. SqlTestFixture: EnsureV013SchemaAsync idempotente + PuntoDeVenta_History en TablesToIgnore + permiso administracion:puntos_de_venta:gestionar en seed canónico + asignación a rol admin. 6. Tests: conteos 22→23 permisos (V013 agrega uno); repository fixtures ignoran PuntoDeVenta_History; test UpdatePdv_WhenPdvInactive eliminado (over-specified — spec no bloquea update en PdV inactivo, solo en Medio padre inactivo; alineado con frontend que permite editar PdV inactivo). Resultado: 190/190 Api.Tests y tests específicos ADM-008 verdes (Domain 13, Application 42, Api 21 = 76 tests nuevos). El único failure residual (AuditEventRepositoryTests.QueryAsync_Limit_EmitsCursor) es pre-existente y no relacionado a ADM-008. Covers: verify report CRITICAL (UQ name mismatch) + WARNINGs descubiertos durante la ejecución (DI registro, temporal tables concurrency, permiso fixture, counts de tests pre-existentes).
This commit is contained in:
@@ -13,7 +13,7 @@ namespace SIGCM2.Application.PuntosDeVenta.Reservar;
|
||||
/// Un TransactionScope ambiente aquí escalaría a DTC → innecesario.
|
||||
/// - NO usa Polly: no está en el proyecto. Retry deadlock con bucle simple.
|
||||
/// - Infrastructure traduce SqlException 1205 → DeadlockTransientException.
|
||||
/// - Backoff en ms: [50, 150, 450] — 3 intentos máximo.
|
||||
/// - Backoff en ms: [25, 75, 200, 500, 1200] — 5 retries máximo (6 intentos totales).
|
||||
/// - La auditoría de reservas corre solo vía Temporal Tables (AD8).
|
||||
/// </summary>
|
||||
public sealed class ReservarNumeroCommandHandler : ICommandHandler<ReservarNumeroCommand, ReservaNumeroDto>
|
||||
@@ -21,7 +21,7 @@ public sealed class ReservarNumeroCommandHandler : ICommandHandler<ReservarNumer
|
||||
private readonly IPuntoDeVentaRepository _repo;
|
||||
private readonly int[] _deadlockBackoffMs;
|
||||
|
||||
private static readonly int[] DefaultBackoffMs = [50, 150, 450];
|
||||
private static readonly int[] DefaultBackoffMs = [25, 75, 200, 500, 1200];
|
||||
|
||||
public ReservarNumeroCommandHandler(IPuntoDeVentaRepository repo)
|
||||
: this(repo, DefaultBackoffMs) { }
|
||||
|
||||
Reference in New Issue
Block a user