reverse-proxy icon indicating copy to clipboard operation
reverse-proxy copied to clipboard

Request timeouts reported as ForwarderError.RequestCanceled instead of RequestTimedOut

Open MihaZupan opened this issue 1 year ago • 3 comments

Hello,

Confirming the same behavior on the 2.2.0 release, but let me add more details. But when the request timed out, it returned a 400 instead of a 504.

Trying to configure timeouts with ForwarderRequestConfig.ActivityTimeout on a cluster and Timeout/TimeoutPolicy on a route, but results are different: the first configuration returns 504 Gateway Timeout, second - 400 Bad Request. Shouldn't the results be the same?

@MihaZupan, created a repository, please have a look. Are you able to create a minimal runnable repro for the issue?

Originally posted by @alekseikhripunov in #2581

MihaZupan avatar Nov 20 '24 14:11 MihaZupan

When using request timeouts (timeout configuration on the route), that timeout works by signaling the HttpContext.RequestAborted CancellationToken.

YARP currently assumes that token getting cancelled is the result of the client disconnecting and reports a 400 status code. We could detect this case by looking for the IHttpRequestTimeoutFeature, similar to how we already handle ActivityTimeouts differently.

https://github.com/microsoft/reverse-proxy/blob/ed43822e2fc0d6006f3ea4085ee48118bc173514/src/ReverseProxy/Forwarder/HttpForwarder.cs#L637-L639

https://github.com/microsoft/reverse-proxy/blob/ed43822e2fc0d6006f3ea4085ee48118bc173514/src/ReverseProxy/Forwarder/HttpForwarder.cs#L665-L670

MihaZupan avatar Nov 20 '24 14:11 MihaZupan

As a workaround, you could insert a middleware along the lines of

app.Use(async (context, next) =>
{
    await next();

    if (context.RequestAborted.IsCancellationRequested &&
        !context.Response.HasStarted &&
        context.Features.Get<IHttpRequestTimeoutFeature>() is { } timeoutFeature &&
        timeoutFeature.RequestTimeoutToken.IsCancellationRequested)
    {
        context.Response.StatusCode = StatusCodes.Status504GatewayTimeout;
    }
});

MihaZupan avatar Nov 20 '24 14:11 MihaZupan

When using request timeouts (timeout configuration on the route), that timeout works by signaling the HttpContext.RequestAborted CancellationToken.

YARP currently assumes that token getting cancelled is the result of the client disconnecting and reports a 400 status code. We could detect this case by looking for the IHttpRequestTimeoutFeature, similar to how we already handle ActivityTimeouts differently.

https://github.com/microsoft/reverse-proxy/blob/ed43822e2fc0d6006f3ea4085ee48118bc173514/src/ReverseProxy/Forwarder/HttpForwarder.cs#L637-L639

https://github.com/microsoft/reverse-proxy/blob/ed43822e2fc0d6006f3ea4085ee48118bc173514/src/ReverseProxy/Forwarder/HttpForwarder.cs#L665-L670

Met the same issue, looking forward the improvement in YARP side.

inforly avatar May 19 '25 12:05 inforly