using Dapper; using FastEndpoints; using Npgsql; using Shared.Operations; namespace Modules.Common.Operations.Retry; public sealed class Endpoint(NpgsqlDataSource dataSource, WorkItemActionRegistry registry) : EndpointWithoutRequest { public override void Configure() { Post("/api/operations/work-items/{id:guid}/retry"); Permissions("common.operations.retry"); } public override async Task HandleAsync(CancellationToken ct) { var id = Route("id"); var tenant = OperationsIdentity.TenantId(User); var actor = OperationsIdentity.UserId(User); await using var connection = await dataSource.OpenConnectionAsync(ct); var key = await connection.QuerySingleOrDefaultAsync(new CommandDefinition(""" select retry_action_key from kbx.work_items where tenant_id=@Tenant and id=@Id and status in ('open','claimed'); """, new { Tenant = tenant, Id = id }, cancellationToken: ct)); if (string.IsNullOrWhiteSpace(key) || !registry.TryGet(key, out var handler) || handler is null) { AddError("이 예외에는 안전한 재처리 동작이 등록되어 있지 않습니다."); await Send.ErrorsAsync(cancellation: ct); return; } await handler.ExecuteAsync(tenant, actor, id, ct); await Send.OkAsync(ct); } }