using FrameworkDAL.Query.EIPConversation.EIPIdempotency; using GB5Shared.DTO.Framework.Login; using GB5Shared.QueryExecutor; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Logging; namespace FrameworkDAL.CustomCode.EIPConversation.EIPIdempotency { public class EIPIdempotencyDAL : IEIPIdempotencyDAL { private readonly IQueryExecutor _qe; private readonly ILogger _logger; public EIPIdempotencyDAL(IQueryExecutor qe, ILogger logger) { _qe = qe ?? throw new ArgumentNullException(nameof(qe)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task TryRecordAsync( string idempotencyKey, string actionName, LoginDTO login, CancellationToken cancellationToken = default) { try { await _qe.ExecuteAsync( login, EIPIdempotencyQB.TRY_RECORD, new { TenantId = login.ClientId, IdempotencyKey = idempotencyKey, ActionName = actionName, UserId = login.UserId }, cancellationToken: cancellationToken).ConfigureAwait(false); return true; // new key — proceed } catch (SqlException ex) when (ex.Number == 2627 || ex.Number == 2601) { // Unique constraint violation: this key was already processed _logger.LogWarning( "Idempotency duplicate blocked | Key={Key} | Action={Action}", idempotencyKey, actionName); return false; } catch (OperationCanceledException) { _logger.LogWarning("Idempotency record cancelled | Key={Key}", idempotencyKey); throw; } catch (Exception ex) { _logger.LogError(ex, "Idempotency record failed | Key={Key}", idempotencyKey); throw; } } } }