using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using IceImportBLL.IceImportRun; using IceImportSL.Parameters.Run; using static GB5Shared.GB5Constant.Constant; namespace IceImportSL.Endpoints.Run; // Best-effort cancellation — see IIceImportRunCancellationRegistry's doc comment for the // single-instance limitation (no distributed cancel signal across replicas in this phase). public class CancelImportRun : BaseEndpoint> { private readonly IIceImportRunBLL _runBll; private readonly IIceImportRunCancellationRegistry _cancellationRegistry; public CancelImportRun(IIceImportRunBLL runBll, IIceImportRunCancellationRegistry cancellationRegistry) { _runBll = runBll; _cancellationRegistry = cancellationRegistry; } public override void Configure() { Post("/IceImport/CancelImportRun"); AllowAnonymous(); } // Mutation endpoint — never cached. protected override string? GetCacheKey(CancelImportRunParameters req, LoginDTO login) => null; protected override async Task> ExecuteAsync( CancelImportRunParameters req, LoginDTO login, CancellationToken ct) { try { // Always flip the DB row first — this is the source of truth and "sticks" even if the // background task is running on a different instance (see UPDATE_STAGE's own // WHERE STATUS IN ('Queued','Running') guard for how that stops further progress there). var message = await _runBll.CancelRunAsync(req.RunId, login, ct).ConfigureAwait(false); // Best-effort: if the background task happens to be in-process on THIS instance, // interrupt it immediately rather than waiting for it to notice the DB state on its // next write. _cancellationRegistry.TryCancel(req.RunId); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( message, CacheKeyLevel.NOT_REQUIRED, login); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } }