question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Problems to cancel a request (CancellationToken)

See original GitHub issue

Expected Behavior

The action of the api does not correctly receive the cancellation token when aborting a request through Ocelot.

Actual Behavior

By calling the api directly and while it is running, I cancel the request. The CancellationToken parameter takes the correct value and the appropriate exception is thrown. On the other hand, if I make the same request through Ocelot, the exception is not thrown.

Steps to Reproduce the Problem

Api Code

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class PaymentsController : ControllerBase
{
    private readonly ILogger logger;

    public PaymentsController(ILogger<Logging> logger)
    {
        this.logger = logger;
    }

    [HttpGet("{id}")]
    [ProducesResponseType(400)]
    [ProducesResponseType(typeof(string), 202)]
    [ApiExplorerSettings(IgnoreApi = true)]
    public async Task<ActionResult<string>> GetAsync(string id, CancellationToken ct)
    {
        try
        {
            Console.WriteLine("Se va a para la ejecución");
            await Task.Delay(5000, ct);
            ct.ThrowIfCancellationRequested();
            Console.WriteLine($"La ejecución continua -{ct.IsCancellationRequested}-");
        }
        catch (Exception ex) when (ex is TaskCanceledException || ex is OperationCanceledException)
        {
            Console.WriteLine("Operación cancelada");
            return BadRequest();
        }

        return Ok("todo OK");
    }
}

Direct request to the api: http://…/api/v1/Payments/2

Hosting environment: Staging
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://*****/api/v1/Payments/2  
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Route matched with {action = "GetAsync", controller = "Payments"}. Executing action LK.Psd2.Api.Controllers.V1.PaymentsController.GetAsync (LK.Psd2.Api)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action method LK.Psd2.Api.Controllers.V1.PaymentsController.GetAsync (LK.Psd2.Api) with arguments (2, System.Threading.CancellationToken) - Validation state: Valid
Se va a para la ejecuci¢n
Operaci¢n cancelada
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action method LK.Psd2.Api.Controllers.V1.PaymentsController.GetAsync (LK.Psd2.Api), returned result Microsoft.AspNetCore.Mvc.BadRequestResult in 37.1519ms.
info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1]
      Executing HttpStatusCodeResult, setting HTTP status code 400
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action LK.Psd2.Api.Controllers.V1.PaymentsController.GetAsync (LK.Psd2.Api) in 416.8234ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 570.0624ms 0 

Request to the api through Ocelot: https://…/api/v1/Payments/2

Ocelot logs:

dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3]
      Hosting starting
Hosting environment: Staging
Application started. Press Ctrl+C to shut down.
dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4]
      Hosting started
dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0]
      Loaded hosting startup assembly LK.Psd2.ApiGw
dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[0]
      Loaded hosting startup assembly Microsoft.AspNetCore.Server.IISIntegration
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET https://******/api/v1/Payments/2  
dbug: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[0]
      Wildcard detected, all requests with hosts will be allowed.
trce: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[0]
      All hosts are allowed.
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: no request id, previousRequestId: no previous request id, message: MiddlewareStarting: Microsoft.AspNetCore.HttpsPolicy.HstsMiddleware; /api/v1/Payments/2
trce: Microsoft.AspNetCore.HttpsPolicy.HstsMiddleware[3]
      Adding HSTS header to response.
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: no request id, previousRequestId: no previous request id, message: MiddlewareStarting: Microsoft.AspNetCore.Builder.UseExtensions+<>c__DisplayClass0_1; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: no request id, previousRequestId: no previous request id, message: MiddlewareStarting: Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: no request id, previousRequestId: no previous request id, message: MiddlewareStarting: TransitionToOcelotMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: no request id, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: ExceptionHandlerMiddleware; /api/v1/Payments/2
dbug: Ocelot.Errors.Middleware.ExceptionHandlerMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: ocelot pipeline started
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: ResponderMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: DownstreamRouteFinderMiddleware; /api/v1/Payments/2
dbug: Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Upstream url path is /api/v1/Payments/2
dbug: Ocelot.DownstreamRouteFinder.Middleware.DownstreamRouteFinderMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: downstream templates are /api/{version}/{everything}
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: SecurityMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: HttpHeadersTransformationMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: DownstreamRequestInitialiserMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: ClientRateLimitMiddleware; /api/v1/Payments/2
info: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /api/{version}/{everything}
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: ReRouteRequestIdMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: AuthenticationMiddleware; /api/v1/Payments/2
info: Ocelot.Authentication.Middleware.AuthenticationMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: No authentication needed for /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: ClaimsToClaimsMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: AuthorisationMiddleware; /api/v1/Payments/2
info: Ocelot.Authorisation.Middleware.AuthorisationMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: /api/{version}/{everything} route does not require user to be authorised
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: ClaimsToHeadersMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: ClaimsToQueryStringMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: LoadBalancingMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: DownstreamUrlCreatorMiddleware; /api/v1/Payments/2
dbug: Ocelot.DownstreamUrlCreator.Middleware.DownstreamUrlCreatorMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Downstream url is http://******/api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: OutputCacheMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareStarted: HttpRequesterMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: HttpRequesterMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: OutputCacheMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: DownstreamUrlCreatorMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: LoadBalancingMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: ClaimsToQueryStringMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: ClaimsToHeadersMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: AuthorisationMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: ClaimsToClaimsMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: AuthenticationMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: ReRouteRequestIdMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: ClientRateLimitMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: DownstreamRequestInitialiserMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: HttpHeadersTransformationMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: SecurityMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: DownstreamRouteFinderMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: ResponderMiddleware; /api/v1/Payments/2
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: Ocelot.MiddlewareFinished: ExceptionHandlerMiddleware; /api/v1/Payments/2
dbug: Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer[1]
      Connection ID "17654110540902969818" disconnecting.
dbug: Ocelot.Requester.Middleware.HttpRequesterMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: setting http response message
dbug: Ocelot.Responder.Middleware.ResponderMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: no pipeline errors, setting and returning completed response
dbug: Ocelot.Errors.Middleware.ExceptionHandlerMiddleware[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: ocelot pipeline finished
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: MiddlewareFinished: TransitionToOcelotMiddleware; 200
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: MiddlewareFinished: Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware; 200
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: MiddlewareFinished: Microsoft.AspNetCore.Builder.UseExtensions+<>c__DisplayClass0_1; 200
trce: Ocelot.Logging.OcelotDiagnosticListener[0]
      requestId: 800031db-0000-f500-b63f-84710c7967bb, previousRequestId: no previous request id, message: MiddlewareFinished: Microsoft.AspNetCore.HttpsPolicy.HstsMiddleware; 200
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 7468.4477ms 200 text/plain; charset=utf-8

api logs:

Hosting environment: Staging
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://******/api/v1/Payments/2  0
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Route matched with {action = "GetAsync", controller = "Payments"}. Executing action LK.Psd2.Api.Controllers.V1.PaymentsController.GetAsync (LK.Psd2.Api)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action method LK.Psd2.Api.Controllers.V1.PaymentsController.GetAsync (LK.Psd2.Api) with arguments (2, System.Threading.CancellationToken) - Validation state: Valid
Se va a para la ejecuci¢n
La ejecuci¢n continua -False-
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action method LK.Psd2.Api.Controllers.V1.PaymentsController.GetAsync (LK.Psd2.Api), returned result Microsoft.AspNetCore.Mvc.OkObjectResult in 5019.3262ms.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1]
      Executing ObjectResult, writing value of type 'System.String'.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action LK.Psd2.Api.Controllers.V1.PaymentsController.GetAsync (LK.Psd2.Api) in 5402.3125ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 5559.3111ms 200 text/plain; charset=utf-8 

Ocelot config:

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{version}/{everything}", 
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "psd2.desa.net", 
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/{everything}",
      "UpstreamHttpMethod": []
    }
  ],
  "GlobalConfiguration": {
    "RequestIdKey": "OcRequestId"
  }
}

Ocelot Startup.cs

public class Startup
{
    private readonly IConfiguration cfg;

    public Startup(IConfiguration configuration) => cfg = configuration;

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder
                    .AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
        });
        services.AddOcelot();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseCors("CorsPolicy");
        app.UseOcelot().Wait();
    }
}

Specifications

  • Version: 13.0.0
  • Platform: .netcore 2.2.2 (Windows Server 2012R2 IIS 8.5)
  • Subsystem:

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:16 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
nicot4ecommented, Apr 14, 2023

@TomPallister please chime in! It seems like the cancellation issue is a show-stopper for quite some people, we are also using a forked version of Ocelot. There is an easy fix (just merge PR #1367)

2reactions
nicot4ecommented, Mar 28, 2023

Please merge PR #1367! I just confirmed that it still is a fully functioning fix for this issue. What are we waiting for? 🙂

Request cancellation is a basic concept; we should be able to rely on Ocelot to handle this correctly.

We were very surprised to find out that it’s (no longer) working correctly, we’re using Ocelot for quite some time now and we think it was functioning in the past (maybe before version 16.0.0?).

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to cancel a CancellationToken
A CancellationToken can only be canceled by its parent CancellationTokenSource . If you don't have access to the parent CTS, you can't cancel...
Read more >
Recommended patterns for CancellationToken
Know when you've passed the point of no cancellation. Don't cancel if you've already incurred side-effects that your method isn't prepared ...
Read more >
Cancellation in Managed Threads
CancellationTokenSource, Object that creates a cancellation token, and also issues the cancellation request for all copies of that token.
Read more >
Cancellation, Part 2: Requesting Cancellation
A CancellationToken can only respond to cancellation requests; the CancellationTokenSource is necessary to request cancellation. So the ...
Read more >
A Deep Dive into C#'s CancellationToken | by Mitesh Shah
Once the IsCancellationRequested property in a cancellation token is set to true , it can't be set to false again and you cant...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found