پیادهسازی اصولی لغو عملیات (Cancellation Support) در تمام لایههای داتنت
نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۵/۲۹ ۱۲:۳۴
آدرس: www.dntips.ir
CancellationToken)، سرور همچنان به اجرای کوئریهای سنگین دیتابیس، پردازشهای CPU و فراخوانیهای I/O ادامه میدهد که نتیجه آن هدررفت مستقیم منابع و اشباع Thread Pool است. استفاده از Copilot برای افزودن قابلیت Cancellation نباید به «لغو ظاهری یا نمادین» (Fake Cancellation) با چک کردن دستی توکن منتهی شود، بلکه باید انتشار پیوسته و معنادار توکن در تمام لایهها تا پایینترین سطح I/O را پیادهسازی کند.cancellationToken.ThrowIfCancellationRequested() در متدها، بدون ارسال توکن به عملیات پایهای دیتابیس یا سوکت شبکه. در این حالت، تا زمانی که کوئری دیتابیس تمام نشود، برنامه متوجه توقف درخواست نمیشود.ATTN یا لغو سوکت به سرور دیتابیس فرستاده شده و پردازش همانجا متوقف شود.ساختار لغو عملیات (CancellationToken) را در تمام زنجیره این سناریو از لایه Controller تا پایگاه داده پیادهسازی کن.الزامات و محورهای ردیابی:
۱. دریافت توکن از درخواست HTTP کلاینت در لایه اکشن کنترلر / Minimal API.
۲. انتقال مستقیم توکن از طریق Interfaceهای لایه سرویس و ریپازیتوری.
۳. اعمال مستقیم توکن روی درایور و متدهای ناهمگام EF Core (مانندToListAsyncیاSaveChangesAsync).
۴. پرهیز از لغو ظاهری (Fake Cancellation) و توضیح دقیق نقطهای که لغو به صورت فیزیکی عملیات I/O را قطع میکند.
۵. مدیریت تمیز استثنای OperationCanceledException بدون لاگهای خطای بحرانی نامرتبط.HttpContext.RequestAborted را به پارامترهای از نوع CancellationToken متصل (Bind) میکند:[HttpGet]
public async Task<ActionResult<IReadOnlyList<OrderResponseDto>>> GetOrdersAsync(
CancellationToken cancellationToken)
{
var orders = await orderService.GetOrdersAsync(cancellationToken);
return Ok(orders);
}public interface IOrderRepository
{
Task<IReadOnlyList<Order>> GetOrdersAsync(CancellationToken cancellationToken);
}
public sealed class OrderRepository(ApplicationDbContext dbContext) : IOrderRepository
{
public async Task<IReadOnlyList<Order>> GetOrdersAsync(CancellationToken cancellationToken)
{
// نقطه اثر واقعی: توکن به صورت مستقیم به درایور پایگاه داده فرستاده میشود
return await dbContext.Orders
.AsNoTracking()
.ToListAsync(cancellationToken);
}
}CancellationTokenSource.CreateLinkedTokenSource: در پردازشهای پسزمینه یا فراخوانی وبسرویسها، گاهی نیاز به اعمال Timeout مشخص در کنار درخواست توقف کاربر وجود دارد:using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token); await externalClient.FetchDataAsync(linkedCts.Token);
OperationCanceledException یا TaskCanceledException یک رفتار طبیعی و مورد انتظار است، نه یک باگ غیرمنتظره (Crash). به Copilot تأکید کنید که هنگام مدیریت خطا در Middlewareها، لغو درخواست را به عنوان خطای سطحی (LogInformation یا LogDebug) لاگ کند، نه به عنوان خطای بحرانی سطح LogError.CancellationToken.None استفاده کنید تا لغو سمت کاربر باعث ناتمام ماندن ثبت اسناد نشود.