Skip to content

Instantly share code, notes, and snippets.

@IlyaNavodkin
Last active February 8, 2025 19:06
Show Gist options
  • Save IlyaNavodkin/19ca2ed0651026c3c4b5510fdc45b794 to your computer and use it in GitHub Desktop.
Save IlyaNavodkin/19ca2ed0651026c3c4b5510fdc45b794 to your computer and use it in GitHub Desktop.
public class IdempotentOperationExecutor
{
private readonly IIdempotencyManagerFactory _factory;
private readonly DbContext _context;
public IdempotentOperationExecutor(IIdempotencyManagerFactory factory, DbContext context)
{
_factory = factory;
_context = context;
}
public async Task<object> ExecuteAsync(
Data data,
Func<Task<OpResult>> operationTask)
{
using var trx = await _context.Database.BeginTransactionAsync();
var manager = _factory.Create<OpResult>(data.IdempotencyKey,
trx: trx.GetDbTransaction(),
context: new IdempotencyContext("authorizeTransaction", new
{
amount = data.Amount,
customerId = data.CustomerId,
}));
var key = await manager.Create();
if (key.HasPayload)
{
await trx.RollbackAsync();
return new
{
id = key.Payload.Id,
createdAt = key.Payload.CreatedAt,
};
}
OpResult result;
try
{
result = await operationTask();
await _context.SaveChangesAsync();
}
catch (Exception)
{
await trx.RollbackAsync();
throw;
}
key = await manager.Update(new OpResult
{
Id = result.Id,
CreatedAt = result.CreatedAt,
});
await trx.CommitAsync();
return new
{
id = key.Payload.Id,
createdAt = key.Payload.CreatedAt,
};
}
}
/// Using sample
public async Task<object> ExampleUsage(IdempotentOperationExecutor executor, Data data)
{
return await executor.ExecuteAsync(data, async () =>
{
await Task.Delay(100);
return new OpResult
{
Id = Guid.NewGuid().ToString(),
CreatedAt = DateTime.UtcNow,
};
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment