🚦 چه زمانی در ASP.NET Core باید از CancellationTokenSource استفاده کنیم؟یکی از قابلیتهایی که از NET 4. به این طرف وارد فریمورک شد، Cooperative Cancellation است.
قبل از آن، برای متوقف کردن Threadها معمولاً از APIهایی مانند
Thread.Abort() استفاده میشد؛ APIهایی که میتوانستند Thread را در هر نقطهای متوقف کنند و باعث ناپایداری برنامه شوند.به همین دلیل مایکروسافت مدل جدیدی را معرفی کرد:
هیچ عملیاتی نباید به زور متوقف شود؛ خود عملیات باید تصمیم بگیرد که چه زمانی متوقف شود.
به این مدل Cooperative Cancellation گفته میشود.
💡 سه بازیگر اصلی در Cancellation
مستندات NET. سه جزء اصلی را معرفی میکنند:
1️⃣
CancellationTokenSourceاین کلاس مسئول ارسال درخواست لغو است.
using var cts = new CancellationTokenSource();
2️⃣
CancellationTokenاین ساختار فقط وضعیت لغو را نگه میدارد.
CancellationToken token = cts.Token;
هرگز خودش عملیات را متوقف نمیکند.
3️⃣ عملیاتی که Token را دریافت میکند
مثلاً:
HttpClient
EF Core
Task.Delay
Stream
File APIs
Parallel APIs
همگی Token را دریافت میکنند.
await Task.Delay(
TimeSpan.FromSeconds(10),
token);
اگر درخواست لغو ارسال شود، خود
Task.Delay تصمیم میگیرد عملیات را متوقف کند.🏗 جریان کار چگونه است؟
CancellationTokenSource
│
│ Cancel()
▼
CancellationToken
│
▼
HttpClient / EF Core / Task / ...
│
▼
OperationCanceledException
نکته مهم:
ء
CancellationTokenSource هیچ Task یا Threadی را Kill نمیکند.فقط اعلام میکند:
"اگر هنوز مشغول کار هستی، لطفاً متوقف شو."
این دقیقاً همان چیزی است که Microsoft از آن با عنوان Cooperative Cancellation یاد میکند.
🎯 حالا سؤال اصلی:
در ASP.NET Core چه زمانی باید خودمان
CancellationTokenSource بسازیم؟✅ سناریو اول: Timeout اختصاصی
فرض کنید فراخوانی یک سرویس پرداخت نباید بیشتر از ۵ ثانیه طول بکشد.
using var cts =
new CancellationTokenSource(
TimeSpan.FromSeconds(5));
await gateway.PayAsync(
request,
cts.Token);
بعد از ۵ ثانیه:
cts.Cancel()
به صورت خودکار اجرا میشود.
طبق مستندات، این یکی از رایجترین کاربردهای
CancellationTokenSource است.✅ سناریو دوم: لغو دستی عملیات
فرض کنید کاربر دکمه Cancel را فشار میدهد.
cts.Cancel();
از این لحظه تمام عملیاتهایی که این Token را دریافت کردهاند متوجه درخواست لغو میشوند.
✅ سناریو سوم: ترکیب چند Token
در ASP.NET Core معمولاً این Token را دارید:
HttpContext.RequestAborted
این Token زمانی Cancel میشود که:
مرورگر بسته شود. Client ارتباط را قطع کند. حالا فرض کنید علاوه بر آن، میخواهید Timeout هم داشته باشید.
مایکروسافت پیشنهاد میکند:
using var timeout =
new CancellationTokenSource(
TimeSpan.FromSeconds(10));
using var linked =
CancellationTokenSource
.CreateLinkedTokenSource(
HttpContext.RequestAborted,
timeout.Token);
در این حالت اگر هر کدام از Tokenها Cancel شوند، عملیات نیز Cancel خواهد شد.
❌ اشتباه رایج
در بسیاری از پروژهها میبینیم:
public async Task Handle()
{
using var cts =
new CancellationTokenSource();
...
}
بدون هیچ دلیل مشخصی.
در حالی که ASP.NET Core خودش Token مناسب را در اختیار شما قرار داده است:
public async Task<IActionResult> Create(
CancellationToken cancellationToken)
اگر فقط میخواهید عملیات در صورت لغو Request متوقف شود، همان Token را به تمام لایهها پاس دهید.
ساخت
CancellationTokenSource جدید، ارتباط عملیات با Request اصلی را قطع میکند.⚠️ نکتهای که خیلیها نمیدانند
ء
CancellationTokenSource از IDisposable پیروی میکند.مایکروسافت صراحتاً توصیه میکند بعد از اتمام کار آن را Dispose کنید.
using var cts =
new CancellationTokenSource();
⚠️ یک باور اشتباه
بعضیها تصور میکنند:
Cancel()
یعنی Task فوراً متوقف میشود.
اما مستندات دقیقاً برعکس این را میگویند.
بعد از ارسال درخواست لغو، این خود عملیات است که باید:
token.ThrowIfCancellationRequested();
را بررسی کند یا APIای که Token را دریافت کرده، به آن واکنش نشان دهد.
به همین دلیل به این مدل میگویند:
Cooperative Cancellation
نه
Forced Cancellation.