Hoje vamos recordar como usar o recurso CancellationToken em uma Web API. |
O recurso CancellationToken é
uma struct que é utilizada para propagar a notificação do cancelamento de
uma operação e pode ser usado para permitir
o cancelamento cooperativo entre threads, itens de trabalho do pool de threads
ou de objetos Task.
Geralmente criamos um token de cancelamento instanciando um objeto CancellationTokenSource que gerencia tokens de cancelamento recuperados de propriedade CancellationTokenSource.Token.
A seguir passamos o token de cancelamento para qualquer número de threads, tarefas ou operações que devem receber aviso de cancelamento. O token não pode ser usado para iniciar o cancelamento.
Quando o objeto proprietário chama CancellationTokenSource.Cancel, a IsCancellationRequested propriedade em cada cópia do token de cancelamento é definida como true. Os objetos que recebem a notificação podem responder de qualquer maneira apropriada.
Para mostrar na prática o uso do
CancellationToken de forma bem simples, vamos criar uma Web API usando o
template padrão do Visual Studio 2022 : ASP.NET Core Web
API.
Teremos um projeto padrão criado que vai exibir a previsão do tempo de forma aleatória.
O código do controlador WeatherForecastController gerado é exibido a seguir:
using Microsoft.AspNetCore.Mvc;
namespace ApiCancellationToken.Controllers;
[ApiController]
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController>
logger)
[HttpGet(Name = "GetWeatherForecast")] await Task.Delay(10_000);
_logger.LogInformation("Finalizando o Request...");
var result =
Enumerable.Range(1, 5).Select(index => new WeatherForecast _logger.LogInformation($"Resultados : {result.Length}");
|
As linhas de código
em destaque foram incluídas para testar a execução do código.
Vamos agora abrir duas janelas no navegador padrão e definir a url para acionar o endpoint.
Para este exemplo o endpoint usado é :
https://localhost:7017/WeatherForecast
Após informar a url completa em cada aba do navegador pressione enter na primeira aba, a seguir abra a segunda aba e pressione enter mas a seguir feche o navegador.
Como temos um delay de 10 segundos podemos verificar na
janela Output o seguinte resultado:
Observe que embora tenhamos cancelado a execução do segundo request, cada request foi completado exibindo o resultado final da operação.
Assim, se nossa aplicação usasse um banco de dados a requisição seria enviada para o banco, mesmo cancelando o request por qualquer motivo.
Para evitar este problema podemos usar o
CancellationToken alterando o código o método
Get conforme abaixo:
[HttpGet(Name =
"GetWeatherForecast")] public async Task<IEnumerable<WeatherForecast>> Get(CancellationToken ct) { try { _logger.LogInformation("Iniciando o Request..."); await Task.Delay(5_000, ct);
_logger.LogInformation("Finalizando o Request...");
var result = Enumerable.Range(1, 5).Select(index => new WeatherForecast _logger.LogInformation($"Resultados : {result.Length}");
return result; |
O código em destaque mostra o uso do CancellationToken e lança uma TaskCanceledException.
Vamos executar o projeto e repetir o procedimento realizado e ver o resultado.
Observe que agora temos a notificação de cancelamento propagada causando o lançamento da exceção do tipo TaskCanceledException.
Embora o exemplo seja o mais básico possível ele mostra os benefícios em usar o recurso CancellationToken nestes cenários. Dentre outras vantagens podemos citar:
Cancelar operações assíncronas ou operações síncronas de longa duração protegendo a CPU de recursos e pools de threads;
Evitar a duplicação de registros ao criar, atualizar ou excluir;
Economizar tempo não executando a tarefa cancelada;
Em resumo, fornecer um token de cancelamento é uma boa prática, pois economiza recursos e tempo.
Referências: