51 lines
1.6 KiB
C#
51 lines
1.6 KiB
C#
using System.Text.Json;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
public class IdempotencyService : IIdempotencyService
|
|
{
|
|
private readonly AppDbContext _db;
|
|
private static readonly TimeSpan DefaultTtl = TimeSpan.FromHours(24);
|
|
|
|
public IdempotencyService(AppDbContext db)
|
|
{
|
|
_db = db;
|
|
}
|
|
|
|
public async Task<IdempotencyRecord?> GetExistingAsync(string idempotencyKey, string operationName)
|
|
{
|
|
var record = await _db.IdempotencyRecords
|
|
.FirstOrDefaultAsync(r =>
|
|
r.IdempotencyKey == idempotencyKey &&
|
|
r.OperationName == operationName &&
|
|
r.ExpiresAt > DateTimeOffset.UtcNow);
|
|
|
|
return record;
|
|
}
|
|
|
|
public Task SaveAsync(string idempotencyKey, string operationName, Guid resourceId,
|
|
int httpStatusCode, object responseBody, TimeSpan? ttl = null)
|
|
{
|
|
var effectiveTtl = ttl ?? DefaultTtl;
|
|
var now = DateTimeOffset.UtcNow;
|
|
|
|
var record = new IdempotencyRecord
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
IdempotencyKey = idempotencyKey,
|
|
OperationName = operationName,
|
|
ResourceId = resourceId,
|
|
HttpStatusCode = httpStatusCode,
|
|
ResponseBodyJson = JsonSerializer.Serialize(responseBody, new JsonSerializerOptions
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
WriteIndented = false
|
|
}),
|
|
CreatedAt = now,
|
|
ExpiresAt = now.Add(effectiveTtl)
|
|
};
|
|
|
|
_db.IdempotencyRecords.Add(record);
|
|
// SaveChanges is called by the caller (within the same transaction)
|
|
return Task.CompletedTask;
|
|
}
|
|
} |