namespace IceImportBLL.IceImportRun; // In-memory, per-instance registry mapping a RunId to the CancellationTokenSource driving its // background pipeline execution — the mechanism CancelImportRun uses to actually interrupt a // still-in-process run on the SAME instance that is executing it. // // Deliberate, documented limitation: this is single-instance, in-memory state (a // ConcurrentDictionary, never a distributed store). If the background task happens to be running on // a different instance than the one that receives the CancelImportRun call (multi-replica // deployment), TryCancel simply returns false for that instance — the run's TICEIMPORTRUN row is // still flipped to 'Cancelled' by IceImportRunBLL.CancelRunAsync regardless (via // IceImportRunQB.CANCEL_RUN), and IceImportRunQB.UPDATE_STAGE's own // "WHERE STATUS IN ('Queued','Running')" guard means the background task's subsequent DB writes // become no-ops even without ever observing the CancellationToken — so cancellation still "sticks" // from the DB's point of view, just without interrupting in-flight work early on another replica. // True cross-instance interruption would need a distributed signal (e.g. Redis pub/sub) — out of // scope for this phase. public interface IIceImportRunCancellationRegistry { // Creates (or replaces) the CancellationTokenSource for runId, linked to callerToken so the // background task still observes the caller's own cancellation (e.g. app shutdown) in addition // to an explicit CancelImportRun. Returns the token the background pipeline should pass through // every pipeline-stage call. CancellationToken Register(long runId, CancellationToken callerToken); // Signals cancellation for runId if it is currently registered on this instance. // Returns true if found and cancelled, false if not tracked here (already completed, or running // on a different instance). bool TryCancel(long runId); // Removes and disposes the CancellationTokenSource for runId — always call this once the // background task reaches a terminal state (success, failure, or cancellation), in a finally // block, to avoid an unbounded dictionary per CLAUDE.md's "Static Collections" guidance. void Complete(long runId); }