{"id":2164,"date":"2023-08-09T11:00:15","date_gmt":"2023-08-09T11:00:15","guid":{"rendered":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/?p=2164"},"modified":"2023-08-09T11:00:15","modified_gmt":"2023-08-09T11:00:15","slug":"la-importancia-de-usar-cancellationtoken-en-nuestras-apis","status":"publish","type":"post","link":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/","title":{"rendered":"La importancia de usar CancellationToken en nuestras APIs"},"content":{"rendered":"<p>Sobre este \u00faltimo punto, vamos a ver un ejemplo a continuaci\u00f3n.<\/p>\n<h2 class=\"wp-block-heading\">Utilizando CancellationToken<\/h2>\n<p class=\"wp-block-paragraph\">Este ejemplo lo vamos a hacer sobre un <em>endpoint<\/em> que llama a un servicio que lo \u00fanico que hace es guardar un registro en una base de datos y esperar 5 segundos antes de materializar la transacci\u00f3n.<\/p>\n<pre class=\"wp-block-code\"><code>public async Task&lt;int&gt; AddAsync(CreatingTask businessModel, CancellationToken cancellationToken = default)\r\n{\r\n    return await unitOfWork.SaveChangesInTransactionAsync(async () =&gt;\r\n    {\r\n        await ValidateEntityToAddAsync(businessModel);\r\n\r\n        var entity = MapCreating(businessModel);\r\n        await _repository.AddAsync(entity, cancellationToken);\r\n        await unitOfWork.SaveChangesAsync(cancellationToken);\r\n\r\n        await Task.Delay(5000, cancellationToken);\r\n\r\n        return entity.Id;\r\n    }, cancellationToken);\r\n}<\/code><\/pre>\n<p class=\"wp-block-paragraph\">En el c\u00f3digo anterior se muestra el servicio que os he comentado. Como puede apreciarse, lo que hace es lanzar algunas validaciones sobre el DTO recibido (<em>ValidateEntityToAddAsync<\/em>), mapear a la entidad utilizada por el repositorio (<em>MapCreating<\/em>) y a\u00f1adir la entidad a la base de datos. Todo ello encapsulado en una transacci\u00f3n que se materializa 5 segundos despu\u00e9s de haberse guardado la entidad. La espera de 5 segundos, obviamente no se ver\u00e1 en un escenario real, pero lo hago para simular una tarea larga.<\/p>\n<p class=\"wp-block-paragraph\">A continuaci\u00f3n se muestran los endpoints que he creado. Uno recibe un <em>CancellationToken<\/em> y otro no.<\/p>\n<pre class=\"wp-block-code\"><code>[HttpPost]\r\n[ProducesResponseType(StatusCodes.Status201Created)]\r\n[ProducesResponseType(StatusCodes.Status400BadRequest)]\r\n[ProducesResponseType(StatusCodes.Status409Conflict)]\r\npublic async Task&lt;IActionResult&gt; Post([FromBody]CreatingTask item, CancellationToken cancellationToken = default)\r\n{\r\n    if (item == null)\r\n        return BadRequest();\r\n\r\n    if (!ModelState.IsValid)\r\n        return BadRequest();\r\n\r\n    int createdId = await _service.AddAsync(item, cancellationToken);\r\n    return Created(nameof(GetById), new { id = createdId });\r\n}\r\n\r\n[HttpPost]\r\n[Route(\"nonCancellable\")]\r\n[ProducesResponseType(StatusCodes.Status201Created)]\r\n[ProducesResponseType(StatusCodes.Status400BadRequest)]\r\n[ProducesResponseType(StatusCodes.Status409Conflict)]\r\npublic async Task&lt;IActionResult&gt; PostNonCancellable([FromBody]CreatingTask item)\r\n{\r\n    if (item == null)\r\n        return BadRequest();\r\n\r\n    if (!ModelState.IsValid)\r\n        return BadRequest();\r\n\r\n    int createdId = await _service.AddAsync(item);\r\n    return Created(nameof(GetById), new { id = createdId });\r\n}<\/code><\/pre>\n<p class=\"wp-block-paragraph\">La gran diferencia entre los dos endpoints, es que uno recibe un <em>CancellationToken<\/em> que pasa al servicio, por lo que la operaci\u00f3n es cancelable. Y el otro no, por lo que, aunque cancelemos la operaci\u00f3n desde el lado cliente, el servidor seguir\u00e1 realizando la tarea y guardar\u00e1 los valores de la tarea en la base de datos.<\/p>\n<p class=\"wp-block-paragraph\">Para probar todo esto, he creado la siguiente bater\u00eda de tests.<\/p>\n<pre class=\"wp-block-code\"><code>private static readonly string url = \"\/api\/task\";\r\nprivate HttpClient _client;\r\n\r\n[TestInitialize]\r\npublic async Task InitDbContext()\r\n{\r\n    \/\/Creates a temporary database and inserts some data to make tests\r\n    WebApplicationFactory&lt;Program&gt; factory = await BuildWebApplicationFactory(Guid.NewGuid().ToString());\r\n\r\n    _client = factory.CreateClient();\r\n    AddApiKeyHeader(_client);\r\n}\r\n\r\n[TestCleanup]\r\npublic async Task RemoveDbContext()\r\n{\r\n    \/\/Removes the temporary database create in the test initialization\r\n    await DeleteDatabase();\r\n    _client.Dispose();\r\n    await Task.CompletedTask;\r\n}\r\n\r\n[TestMethod]\r\npublic async Task post_created()\r\n{\r\n    CreatingTask creatingTask = new CreatingTask { TaskListId = 2, Description = \"Task 8\" };\r\n    StringContent content = new StringContent(JsonConvert.SerializeObject(creatingTask), Encoding.UTF8, \"application\/json\");\r\n    HttpResponseMessage response = await _client.PostAsync(url, content);\r\n\r\n    Assert.AreEqual(System.Net.HttpStatusCode.Created, response.StatusCode);\r\n}\r\n\r\n[TestMethod]\r\npublic async Task post_cancelled()\r\n{\r\n    CancellationTokenSource source = new CancellationTokenSource(3000);\r\n    CreatingTask creatingTask = new CreatingTask { TaskListId = 2, Description = \"Task 9\" };\r\n    StringContent content = new StringContent(JsonConvert.SerializeObject(creatingTask), Encoding.UTF8, \"application\/json\");\r\n    await Assert.ThrowsExceptionAsync&lt;OperationCanceledException&gt;(async() =&gt; await _client.PostAsync(url, content, source.Token));\r\n}\r\n\r\n[TestMethod]\r\npublic async Task post_non_cancellable_created()\r\n{\r\n    CreatingTask creatingTask = new CreatingTask { TaskListId = 2, Description = \"Task 10\" };\r\n    StringContent content = new StringContent(JsonConvert.SerializeObject(creatingTask), Encoding.UTF8, \"application\/json\");\r\n    HttpResponseMessage response = await _client.PostAsync($\"{url}\/nonCancellable\", content);\r\n\r\n    Assert.AreEqual(System.Net.HttpStatusCode.Created, response.StatusCode);\r\n}\r\n\r\n[TestMethod]\r\npublic async Task post_non_cancellable_cancelled()\r\n{\r\n    CancellationTokenSource source = new CancellationTokenSource(3000);\r\n    CreatingTask creatingTask = new CreatingTask { TaskListId = 2, Description = \"Task 11\" };\r\n    StringContent content = new StringContent(JsonConvert.SerializeObject(creatingTask), Encoding.UTF8, \"application\/json\");\r\n    await Assert.ThrowsExceptionAsync&lt;OperationCanceledException&gt;(async() =&gt; await _client.PostAsync($\"{url}\/nonCancellable\", content, source.Token));\r\n}<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Todos los tests anteriores se completan correctamente, pero si echamos un vistazo al resultado de la base de datos en los dos m\u00e9todos que se cancelan, vemos algo que marca la diferencia.<\/p>\n<p class=\"wp-block-paragraph\"><em>post_cancelled<\/em> llama al <em>endpoint<\/em> que permite cancelaci\u00f3n y cancela la petici\u00f3n a los 3 segundos, por lo que la tarea cuya descripci\u00f3n es <em>Task 9<\/em> no se a\u00f1ade a la base de datos. Recordemos que el servicio materializa la transacci\u00f3n que guarda los valores en la base de datos tras un <em>delay<\/em> de 5 segundos.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" class=\"wp-image-856 aligncenter\" src=\"https:\/\/jorgediegocrespo.files.wordpress.com\/2023\/08\/image.png?w=455\" alt=\"\" \/><\/figure>\n<\/div>\n<p class=\"wp-block-paragraph\">En cambio, <em>post_non_cancellable_cancelled<\/em> llama al endpoint que no permite cancelaci\u00f3n, por lo que, aunque cancelemos la petici\u00f3n, la transacci\u00f3n se materializa en la base de datos y la tarea cuya descripci\u00f3n es <em>Task 11<\/em> se guarda.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" class=\"wp-image-857 aligncenter\" src=\"https:\/\/jorgediegocrespo.files.wordpress.com\/2023\/08\/screenshot-2023-08-01-at-08.33.03.png?w=455\" alt=\"\" \/><\/figure>\n<\/div>\n<p class=\"wp-block-paragraph\">Con todo lo anterior, queda demostrado que el uso de <em>CancellationToken<\/em> es una pr\u00e1ctica recomendada, sobretodo en escenarios donde las operaciones pueden ser costosas o tomar un tiempo significativo para completarse.<\/p>\n<p>Puedes visitar el <a href=\"https:\/\/jorgediegocrespo.wordpress.com\/2023\/08\/01\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/\">post original en el blog de Jorge Diego Crespo<\/a><\/p>\n<p><!-- \/wp:paragraph --><!-- wp:post-content --><!-- wp:paragraph --><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2168\" src=\"http:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token.jpg\" alt=\"\" width=\"1014\" height=\"598\" srcset=\"https:\/\/encaminablogs.wpenginepowered.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token.jpg 1014w, https:\/\/encaminablogs.wpenginepowered.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token-300x177.jpg 300w, https:\/\/encaminablogs.wpenginepowered.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token-768x453.jpg 768w, https:\/\/encaminablogs.wpenginepowered.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token-610x360.jpg 610w\" sizes=\"auto, (max-width: 1014px) 100vw, 1014px\" \/>Hoy vengo a contaros por qu\u00e9 es importante utilizar tokens de cancelaci\u00f3n en los endpoints de nuestras <em>APIs<\/em>.<\/p>\n<p>(Puedes visitar el <a href=\"https:\/\/jorgediegocrespo.wordpress.com\/2023\/08\/01\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/\">post original en el blog de Jorge Diego Crespo)<\/a><\/p>\n<p><!--more--><\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Primero de todo. <strong>\u00bfQu\u00e9 es un token de cancelaci\u00f3n (<em>CancellationToken<\/em> de aqu\u00ed en adelante)?<\/strong><\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Un <em>CancellationToken<\/em> es un mecanismo de cancelaci\u00f3n proporcionado por <em>dotNet<\/em> que se utiliza para solicitar la cancelaci\u00f3n de una operaci\u00f3n en progreso. Por ejemplo, supongamos que tenemos un <em>endpoint<\/em> que realiza una tarea larga o costosa, como realizar una consulta a una base de datos o llamar a un servicio externo. Si un cliente realiza una solicitud y luego cambia de opini\u00f3n o cierra la conexi\u00f3n, puede ser deseable cancelar la tarea en curso para liberar recursos y evitar un trabajo innecesario.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Una vez que sabemos qu\u00e9 es un <em>CancellationToken<\/em> toca contestar la siguiente pregunta. <strong>\u00bfPor qu\u00e9 debo usarlo?<\/strong><\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Existen varias razones para usarlo. Aqu\u00ed enumero algunas de ellas:<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:list --><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul><!-- wp:list-item --><\/p>\n<li><strong>Mejora la experiencia del cliente:<\/strong> Especialmente en escenarios donde las solicitudes son costosas o requieren mucho tiempo. Si un usuario cancela una de esas costosas operaciones, no tiene sentido que el servidor siga realizando un trabajo innecesario. De esta manera el servidor queda liberado para contestar otras peticiones de forma m\u00e1s r\u00e1pida.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><!-- \/wp:list-item --><\/p>\n<p><!-- wp:list-item --><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li><strong>Ahorro de recursos:<\/strong> Muy relacionada con la anterior. Al permitir la cancelaci\u00f3n, se pueden liberar recursos valiosos en el servidor si una solicitud ya no es necesaria. Esto ayuda a utilizar de manera m\u00e1s eficiente los recursos del servidor.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><!-- \/wp:list-item --><\/p>\n<p><!-- wp:list-item --><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li><strong>Prevenci\u00f3n de operaciones innecesarias:<\/strong> Al utilizar <em>CancellationToken<\/em>, se pueden interrumpir operaciones que se vuelven innecesarias si el cliente decide cancelar la solicitud. Esto ayuda a evitar que se completen tareas que puede incluso hacer modificaciones en los datos de nuestra aplicaci\u00f3n, provocando errores, dado que la operaci\u00f3n deber\u00eda haberse cancelado.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><!-- \/wp:list-item --><!-- \/wp:list --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Sobre este \u00faltimo punto, vamos a ver un ejemplo a continuaci\u00f3n.<\/p>\n<p><!-- wp:heading --><\/p>\n<h2 class=\"wp-block-heading\">Utilizando CancellationToken<\/h2>\n<p><!-- \/wp:heading --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Este ejemplo lo vamos a hacer sobre un <em>endpoint<\/em> que llama a un servicio que lo \u00fanico que hace es guardar un registro en una base de datos y esperar 5 segundos antes de materializar la transacci\u00f3n.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:code --><\/p>\n<pre class=\"wp-block-code\"><code>public async Task&lt;int&gt; AddAsync(CreatingTask businessModel, CancellationToken cancellationToken = default)\r\n{\r\n    return await unitOfWork.SaveChangesInTransactionAsync(async () =&gt;\r\n    {\r\n        await ValidateEntityToAddAsync(businessModel);\r\n\r\n        var entity = MapCreating(businessModel);\r\n        await _repository.AddAsync(entity, cancellationToken);\r\n        await unitOfWork.SaveChangesAsync(cancellationToken);\r\n\r\n        await Task.Delay(5000, cancellationToken);\r\n\r\n        return entity.Id;\r\n    }, cancellationToken);\r\n}<\/code><\/pre>\n<p><!-- \/wp:code --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>En el c\u00f3digo anterior se muestra el servicio que os he comentado. Como puede apreciarse, lo que hace es lanzar algunas validaciones sobre el DTO recibido (<em>ValidateEntityToAddAsync<\/em>), mapear a la entidad utilizada por el repositorio (<em>MapCreating<\/em>) y a\u00f1adir la entidad a la base de datos. Todo ello encapsulado en una transacci\u00f3n que se materializa 5 segundos despu\u00e9s de haberse guardado la entidad. La espera de 5 segundos, obviamente no se ver\u00e1 en un escenario real, pero lo hago para simular una tarea larga.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>A continuaci\u00f3n se muestran los endpoints que he creado. Uno recibe un <em>CancellationToken<\/em> y otro no.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:code --><\/p>\n<pre class=\"wp-block-code\"><code>[HttpPost]\r\n[ProducesResponseType(StatusCodes.Status201Created)]\r\n[ProducesResponseType(StatusCodes.Status400BadRequest)]\r\n[ProducesResponseType(StatusCodes.Status409Conflict)]\r\npublic async Task&lt;IActionResult&gt; Post([FromBody]CreatingTask item, CancellationToken cancellationToken = default)\r\n{\r\n    if (item == null)\r\n        return BadRequest();\r\n\r\n    if (!ModelState.IsValid)\r\n        return BadRequest();\r\n\r\n    int createdId = await _service.AddAsync(item, cancellationToken);\r\n    return Created(nameof(GetById), new { id = createdId });\r\n}\r\n\r\n[HttpPost]\r\n[Route(\"nonCancellable\")]\r\n[ProducesResponseType(StatusCodes.Status201Created)]\r\n[ProducesResponseType(StatusCodes.Status400BadRequest)]\r\n[ProducesResponseType(StatusCodes.Status409Conflict)]\r\npublic async Task&lt;IActionResult&gt; PostNonCancellable([FromBody]CreatingTask item)\r\n{\r\n    if (item == null)\r\n        return BadRequest();\r\n\r\n    if (!ModelState.IsValid)\r\n        return BadRequest();\r\n\r\n    int createdId = await _service.AddAsync(item);\r\n    return Created(nameof(GetById), new { id = createdId });\r\n}<\/code><\/pre>\n<p><!-- \/wp:code --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>La gran diferencia entre los dos endpoints, es que uno recibe un <em>CancellationToken<\/em> que pasa al servicio, por lo que la operaci\u00f3n es cancelable. Y el otro no, por lo que, aunque cancelemos la operaci\u00f3n desde el lado cliente, el servidor seguir\u00e1 realizando la tarea y guardar\u00e1 los valores de la tarea en la base de datos.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Para probar todo esto, he creado la siguiente bater\u00eda de tests.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:code --><\/p>\n<pre class=\"wp-block-code\"><code>private static readonly string url = \"\/api\/task\";\r\nprivate HttpClient _client;\r\n\r\n[TestInitialize]\r\npublic async Task InitDbContext()\r\n{\r\n    \/\/Creates a temporary database and inserts some data to make tests\r\n    WebApplicationFactory&lt;Program&gt; factory = await BuildWebApplicationFactory(Guid.NewGuid().ToString());\r\n\r\n    _client = factory.CreateClient();\r\n    AddApiKeyHeader(_client);\r\n}\r\n\r\n[TestCleanup]\r\npublic async Task RemoveDbContext()\r\n{\r\n    \/\/Removes the temporary database create in the test initialization\r\n    await DeleteDatabase();\r\n    _client.Dispose();\r\n    await Task.CompletedTask;\r\n}\r\n\r\n[TestMethod]\r\npublic async Task post_created()\r\n{\r\n    CreatingTask creatingTask = new CreatingTask { TaskListId = 2, Description = \"Task 8\" };\r\n    StringContent content = new StringContent(JsonConvert.SerializeObject(creatingTask), Encoding.UTF8, \"application\/json\");\r\n    HttpResponseMessage response = await _client.PostAsync(url, content);\r\n\r\n    Assert.AreEqual(System.Net.HttpStatusCode.Created, response.StatusCode);\r\n}\r\n\r\n[TestMethod]\r\npublic async Task post_cancelled()\r\n{\r\n    CancellationTokenSource source = new CancellationTokenSource(3000);\r\n    CreatingTask creatingTask = new CreatingTask { TaskListId = 2, Description = \"Task 9\" };\r\n    StringContent content = new StringContent(JsonConvert.SerializeObject(creatingTask), Encoding.UTF8, \"application\/json\");\r\n    await Assert.ThrowsExceptionAsync&lt;OperationCanceledException&gt;(async() =&gt; await _client.PostAsync(url, content, source.Token));\r\n}\r\n\r\n[TestMethod]\r\npublic async Task post_non_cancellable_created()\r\n{\r\n    CreatingTask creatingTask = new CreatingTask { TaskListId = 2, Description = \"Task 10\" };\r\n    StringContent content = new StringContent(JsonConvert.SerializeObject(creatingTask), Encoding.UTF8, \"application\/json\");\r\n    HttpResponseMessage response = await _client.PostAsync($\"{url}\/nonCancellable\", content);\r\n\r\n    Assert.AreEqual(System.Net.HttpStatusCode.Created, response.StatusCode);\r\n}\r\n\r\n[TestMethod]\r\npublic async Task post_non_cancellable_cancelled()\r\n{\r\n    CancellationTokenSource source = new CancellationTokenSource(3000);\r\n    CreatingTask creatingTask = new CreatingTask { TaskListId = 2, Description = \"Task 11\" };\r\n    StringContent content = new StringContent(JsonConvert.SerializeObject(creatingTask), Encoding.UTF8, \"application\/json\");\r\n    await Assert.ThrowsExceptionAsync&lt;OperationCanceledException&gt;(async() =&gt; await _client.PostAsync($\"{url}\/nonCancellable\", content, source.Token));\r\n}<\/code><\/pre>\n<p><!-- \/wp:code --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Todos los tests anteriores se completan correctamente, pero si echamos un vistazo al resultado de la base de datos en los dos m\u00e9todos que se cancelan, vemos algo que marca la diferencia.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p><em>post_cancelled<\/em> llama al <em>endpoint<\/em> que permite cancelaci\u00f3n y cancela la petici\u00f3n a los 3 segundos, por lo que la tarea cuya descripci\u00f3n es <em>Task 9<\/em> no se a\u00f1ade a la base de datos. Recordemos que el servicio materializa la transacci\u00f3n que guarda los valores en la base de datos tras un <em>delay<\/em> de 5 segundos.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:image {\"align\":\"center\",\"id\":856,\"sizeSlug\":\"large\",\"linkDestination\":\"none\"} --><\/p>\n<figure class=\"wp-block-image aligncenter size-large\"><img decoding=\"async\" class=\"wp-image-856 aligncenter\" src=\"https:\/\/jorgediegocrespo.files.wordpress.com\/2023\/08\/image.png?w=455\" alt=\"\" \/><\/figure>\n<p><!-- \/wp:image --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>En cambio, <em>post_non_cancellable_cancelled<\/em> llama al endpoint que no permite cancelaci\u00f3n, por lo que, aunque cancelemos la petici\u00f3n, la transacci\u00f3n se materializa en la base de datos y la tarea cuya descripci\u00f3n es <em>Task 11<\/em> se guarda.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:image {\"align\":\"center\",\"id\":857,\"sizeSlug\":\"large\",\"linkDestination\":\"none\"} --><\/p>\n<figure class=\"wp-block-image aligncenter size-large\"><img decoding=\"async\" class=\"wp-image-857 aligncenter\" src=\"https:\/\/jorgediegocrespo.files.wordpress.com\/2023\/08\/screenshot-2023-08-01-at-08.33.03.png?w=455\" alt=\"\" \/><\/figure>\n<p><!-- \/wp:image --><\/p>\n<p><!-- wp:paragraph --><\/p>\n<p>Con todo lo anterior, queda demostrado que el uso de <em>CancellationToken<\/em> es una pr\u00e1ctica recomendada, sobretodo en escenarios donde las operaciones pueden ser costosas o tomar un tiempo significativo para completarse.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p>Puedes visitar el <a href=\"https:\/\/jorgediegocrespo.wordpress.com\/2023\/08\/01\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/\">post original en el blog de Jorge Diego Crespo<\/a><\/p>\n<p><!-- \/wp:post-content --><\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content --><span class=\"et_bloom_bottom_trigger\"><\/span>","protected":false},"excerpt":{"rendered":"<p>Hoy vengo a contaros por qu\u00e9 es importante utilizar tokens de cancelaci\u00f3n en los endpoints de nuestras APIs. (Puedes visitar el post original en el blog de Jorge Diego Crespo)<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":212,"featured_media":2168,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[70,140],"tags":[93,92,141,142,143],"class_list":["post-2164","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-cloud","tag-net","tag-api","tag-cancellation-token","tag-dotnet","tag-endpoint"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v18.2.1 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>La importancia de usar CancellationToken en nuestras APIs - Piensa en software, desarrolla en colores<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"La importancia de usar CancellationToken en nuestras APIs\" \/>\n<meta property=\"og:description\" content=\"Hoy vengo a contaros por qu\u00e9 es importante utilizar tokens de cancelaci\u00f3n en los endpoints de nuestras APIs. (Puedes visitar el post original en el blog de Jorge Diego Crespo)\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/\" \/>\n<meta property=\"og:site_name\" content=\"Piensa en software, desarrolla en colores\" \/>\n<meta property=\"article:published_time\" content=\"2023-08-09T11:00:15+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1014\" \/>\n\t<meta property=\"og:image:height\" content=\"598\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Jorge Diego\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jorge Diego\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/\"},\"author\":{\"name\":\"Jorge Diego\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/#\\\/schema\\\/person\\\/db467d392da36cf2deba504fbb9eeb3e\"},\"headline\":\"La importancia de usar CancellationToken en nuestras APIs\",\"datePublished\":\"2023-08-09T11:00:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/\"},\"wordCount\":718,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/wp-content\\\/uploads\\\/sites\\\/21\\\/2023\\\/08\\\/cancellation-token.jpg\",\"keywords\":[\".net\",\"API\",\"cancellation token\",\"dotNET\",\"endpoint\"],\"articleSection\":[\".NET\",\"cloud\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/\",\"name\":\"La importancia de usar CancellationToken en nuestras APIs - Piensa en software, desarrolla en colores\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/wp-content\\\/uploads\\\/sites\\\/21\\\/2023\\\/08\\\/cancellation-token.jpg\",\"datePublished\":\"2023-08-09T11:00:15+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/#\\\/schema\\\/person\\\/db467d392da36cf2deba504fbb9eeb3e\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\\\/#primaryimage\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/wp-content\\\/uploads\\\/sites\\\/21\\\/2023\\\/08\\\/cancellation-token.jpg\",\"contentUrl\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/wp-content\\\/uploads\\\/sites\\\/21\\\/2023\\\/08\\\/cancellation-token.jpg\",\"width\":1014,\"height\":598},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/#website\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/\",\"name\":\"Piensa en software, desarrolla en colores\",\"description\":\"Las ventajas que te ofrece Microsoft Azure y el mundo.NET\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/#\\\/schema\\\/person\\\/db467d392da36cf2deba504fbb9eeb3e\",\"name\":\"Jorge Diego\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4dc904b19ec9f1309fdccfd8a3c7520f3f89fe1efba301130bbc6ca84e3f6d85?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4dc904b19ec9f1309fdccfd8a3c7520f3f89fe1efba301130bbc6ca84e3f6d85?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4dc904b19ec9f1309fdccfd8a3c7520f3f89fe1efba301130bbc6ca84e3f6d85?s=96&d=mm&r=g\",\"caption\":\"Jorge Diego\"},\"description\":\"Soy un apasionado del desarrollo de software. Me encanta mi trabajo y mantenerme al d\u00eda haciendo cursos, investigando, realizando proyectos personales, etc. Principalmente trabajo con tecnolog\u00eda .NET. Asimismo, me interesa much\u00edsimo el mundo de la productividad personal. Adem\u00e1s del desarrollo tengo otras muchas aficiones: viajar, deporte, gastronom\u00eda, fotograf\u00eda\u2026y sobre todo, pasar tiempo con mi familia.\",\"url\":\"https:\\\/\\\/blogs.encamina.com\\\/piensa-en-software-desarrolla-en-colores\\\/author\\\/jdiego\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"La importancia de usar CancellationToken en nuestras APIs - Piensa en software, desarrolla en colores","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/","og_locale":"es_ES","og_type":"article","og_title":"La importancia de usar CancellationToken en nuestras APIs","og_description":"Hoy vengo a contaros por qu\u00e9 es importante utilizar tokens de cancelaci\u00f3n en los endpoints de nuestras APIs. (Puedes visitar el post original en el blog de Jorge Diego Crespo)","og_url":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/","og_site_name":"Piensa en software, desarrolla en colores","article_published_time":"2023-08-09T11:00:15+00:00","og_image":[{"width":1014,"height":598,"url":"http:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token.jpg","type":"image\/jpeg"}],"author":"Jorge Diego","twitter_card":"summary_large_image","twitter_misc":{"Escrito por":"Jorge Diego","Tiempo de lectura":"6 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/#article","isPartOf":{"@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/"},"author":{"name":"Jorge Diego","@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/#\/schema\/person\/db467d392da36cf2deba504fbb9eeb3e"},"headline":"La importancia de usar CancellationToken en nuestras APIs","datePublished":"2023-08-09T11:00:15+00:00","mainEntityOfPage":{"@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/"},"wordCount":718,"commentCount":0,"image":{"@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token.jpg","keywords":[".net","API","cancellation token","dotNET","endpoint"],"articleSection":[".NET","cloud"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/","url":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/","name":"La importancia de usar CancellationToken en nuestras APIs - Piensa en software, desarrolla en colores","isPartOf":{"@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/#primaryimage"},"image":{"@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/#primaryimage"},"thumbnailUrl":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token.jpg","datePublished":"2023-08-09T11:00:15+00:00","author":{"@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/#\/schema\/person\/db467d392da36cf2deba504fbb9eeb3e"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/la-importancia-de-usar-cancellationtoken-en-nuestras-apis\/#primaryimage","url":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token.jpg","contentUrl":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-content\/uploads\/sites\/21\/2023\/08\/cancellation-token.jpg","width":1014,"height":598},{"@type":"WebSite","@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/#website","url":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/","name":"Piensa en software, desarrolla en colores","description":"Las ventajas que te ofrece Microsoft Azure y el mundo.NET","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Person","@id":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/#\/schema\/person\/db467d392da36cf2deba504fbb9eeb3e","name":"Jorge Diego","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/secure.gravatar.com\/avatar\/4dc904b19ec9f1309fdccfd8a3c7520f3f89fe1efba301130bbc6ca84e3f6d85?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/4dc904b19ec9f1309fdccfd8a3c7520f3f89fe1efba301130bbc6ca84e3f6d85?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4dc904b19ec9f1309fdccfd8a3c7520f3f89fe1efba301130bbc6ca84e3f6d85?s=96&d=mm&r=g","caption":"Jorge Diego"},"description":"Soy un apasionado del desarrollo de software. Me encanta mi trabajo y mantenerme al d\u00eda haciendo cursos, investigando, realizando proyectos personales, etc. Principalmente trabajo con tecnolog\u00eda .NET. Asimismo, me interesa much\u00edsimo el mundo de la productividad personal. Adem\u00e1s del desarrollo tengo otras muchas aficiones: viajar, deporte, gastronom\u00eda, fotograf\u00eda\u2026y sobre todo, pasar tiempo con mi familia.","url":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/author\/jdiego\/"}]}},"_links":{"self":[{"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/posts\/2164","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/users\/212"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/comments?post=2164"}],"version-history":[{"count":0,"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/posts\/2164\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/media\/2168"}],"wp:attachment":[{"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/media?parent=2164"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/categories?post=2164"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.encamina.com\/piensa-en-software-desarrolla-en-colores\/wp-json\/wp\/v2\/tags?post=2164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}