Vấn đề đặt ra
- Bạn đã bao giờ vào một trang web. Gửi một request nào đó nhưng trang web chỉ đứng yên mãi mà không load được dữ liệu mới chưa.
- Lúc này bạn sẽ làm gì. Ấn dừng, thoát web, hay f5 lại web để load lại trang.
- Khi trang web đang bị “đơ”. Bạn nhấn f5 gọi là request 2 đi. Thì request 1 sẽ kết thúc. Trang web sẽ trả về cho bạn dữ liệu ở request 2. Cái này đúng không cần bàn cãi nữa rồi
- Nhưng ở phía máy chủ thì sao. Hành động stop hay f5 của bạn sẽ không cho máy chủ biết rằng cái request đó bị dừng hay không.
- To tát hơn một chút giả sử bạn f5 trang web của bạn 5 lần liên tục thì máy chủ sẽ thực thi request đó 5 lần. Trong khi bạn chỉ cần cái kết quả ở lần cuối cùng.
Ví dụ ban đầu.
- Ở đây mk sẽ giả định một request MVC có thể mất chút thời gian để hoàn thành trước khi có phản hồi cho người dùng. Trong khi request đó đang được xử lý thì người dùng có thể hủy yêu cầu hoặc f5 trang web
- Request MVC đơn giản sẽ là đợi 10 giây trước khi trả kết quả cho người dùng.
Task.Delay(10_000);
sẽ giả định cho công việc mất nhiều thời gian
public class SlowRequestController : Controller
{
private readonly ILogger _logger;
public SlowRequestController(ILogger<SlowRequestController> logger)
{
_logger = logger;
}
[HttpGet("/slowtest")]
public async Task<string> Get()
{
_logger.LogInformation("Starting to do slow work");
// slow async action, e.g. call external api
await Task.Delay(10_000);
var message = "Finished slow delay of 10 seconds.";
_logger.LogInformation(message);
return message;
}
}
- Khi chạy request
URL /slowtest
thì sau 10 giây chúng ta có kết quả - Kiểm tra log
- Bây giờ tới lúc thực hiện thao tác f5 trang web. Trang web sẽ không bao giờ nhận được phản hồi từ request 1. Nhưng trong log thì máy chủ vẫn thực hiện cả request 1 và 2.
- ASP.NET Core cung cấp một cơ chế để máy chủ web báo hiệu khi một yêu cầu bị hủy bằng cách sử dụng a CancellationToken. Điều này được hiển thị dưới dạng HttpContext.RequestAborted, nhưng bạn cũng có thể tự động đưa nó vào các hành động của mình bằng cách sử dụng model binding.
Using CancellationTokens in your MVC Actions
-
CancellationTokens là các đối tượng nhẹ được tạo ra bởi a CancellationTokenSource.
-
Khi một CancellationTokenSource bị hủy bỏ, nó sẽ thông báo cho tất cả những người tiêu dùng của CancellationToken. Điều này cho phép một vị trí trung tâm thông báo cho tất cả các đường dẫn mã trong ứng dụng của bạn rằng việc hủy được yêu cầu.
-
Khi bị hủy, thuộc IsCancellationRequestedtính của mã thông báo hủy sẽ được đặt thành True, để cho biết rằng mã CancellationTokenSourceđã bị hủy.
-
Tùy thuộc vào cách bạn đang sử dụng mã thông báo, bạn có thể cần hoặc không cần tự kiểm tra thuộc tính này.
-
Bây giờ hãy xem cách sử dụng a CancellationTokentrong các phương thức.
-
Đoạn code dưới đây cho thấy cách chúng ta có thể móc vào trung tâm CancellationTokenSourcecho yêu cầu, bằng cách đưa một CancellationTokenvào phương thức hành động và truyền tham số vào lệnh Task.Delay();
public class SlowRequestController : Controller
{
private readonly ILogger _logger;
public SlowRequestController(ILogger<SlowRequestController> logger)
{
_logger = logger;
}
[HttpGet("/slowtest")]
public async Task<string> Get(CancellationToken cancellationToken)
{
_logger.LogInformation("Starting to do slow work");
// slow async action, e.g. call external api
await Task.Delay(10_000, cancellationToken);
var message = "Finished slow delay of 10 seconds.";
_logger.LogInformation(message);
return message;
}
}
- Với thay đổi bên trên. Chúng ta lại thực hiện request 1 xong rồi f5 để thực hiện request 2
- Log lúc này sẽ show cho chúng ta thấy request 1 sẽ không hoàn thành mà ném ra TaskCancelledException còn request 2 vẫn được thực thi như bình thường.
Checking the cancellation state
- Nếu bạn đang gọi một phương thức tích hợp hỗ trợ mã thông báo hủy, như Task.Delay() hoặc HttpClient.SendAsync(), thì bạn có thể truyền token vào như trên và để phương thức bên trong thực hiện việc hủy request cho bạn.
- Trong các trường hợp khác, bạn có thể có một số công việc đồng bộ đang thực hiện mà bạn muốn có thể hủy bỏ.
- Một giải pháp đơn giản để có thể hủy bỏ việc tạo báo cáo này giữa chừng là kiểm tra CancellationTokenbên trong vòng lặp for.
- Ví dụ sau đại diện cho loại tình huống này bằng cách lặp lại 10 lần và thực hiện một số công việc đồng bộ (không thể hủy bỏ), được biểu thị bằng lệnh gọi tới Thread.Sleep().
- Khi bắt đầu mỗi vòng lặp, kiểm tra mã thông báo hủy và throw ra nếu việc hủy đã được yêu cầu. Điều này cho phép chúng ta cancel request vào một quy trình đồng bộ.
public class SlowRequestController : Controller
{
private readonly ILogger _logger;
public SlowRequestController(ILogger<SlowRequestController> logger)
{
_logger = logger;
}
[HttpGet("/slowtest")]
public async Task<string> Get(CancellationToken cancellationToken)
{
_logger.LogInformation("Starting to do slow work");
for(var i=0; i<10; i++)
{
cancellationToken.ThrowIfCancellationRequested();
// slow non-cancellable work
Thread.Sleep(1000);
}
var message = "Finished slow delay of 10 seconds.";
_logger.LogInformation(message);
return message;
}
}
Nguồn: viblo.asia