Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async HTTP Trigger Function Does Not Cancel Cleanly #10739

Closed
david-maw opened this issue Jan 14, 2025 · 4 comments
Closed

Async HTTP Trigger Function Does Not Cancel Cleanly #10739

david-maw opened this issue Jan 14, 2025 · 4 comments
Assignees

Comments

@david-maw
Copy link

An isolated async function with a CancellationToken parameter correctly sets IsCancelRequested when a client disconnects while the function is running but it also:

  1. Throws a TaskCancelled exception (which can be caught in the function)
  2. Even if it is caught, reports "An exception was thrown by the invocation"

I'm new to Azure Functions so I may have missed something obvious, but I'd expected to see IsCancelRequested set and nothing else (no exception unless I threw an uncaught one).

The test is simply to invoke the sample function below from a browser then cancel the request before it has chance to complete.

My sample Function code below is just the default code generated by VS with some minor additions.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace FunctionAppCancel
{
    public class Function1
    {
        private readonly ILogger<Function1> _logger;

        public Function1(ILogger<Function1> logger)
        {
            _logger = logger;
        }

        [Function("Function1")]
        public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req, CancellationToken cancellationToken)
        {
            try
            {
                _logger.LogInformation("C# HTTP trigger function processed a request.");
                await Task.Delay(5000, cancellationToken);

                if (cancellationToken.IsCancellationRequested)
                {
                    _logger.LogError("C# HTTP trigger function canceled.");
                    return new OkResult();
                }
                return new OkObjectResult("Welcome to Azure Functions!");
            }
            catch (Exception ex)
            {
                _logger.LogError($"C# HTTP trigger function threw exception {ex.Message}");
                return new BadRequestResult();
            }
        }
    }
}

The local emulator shows:

Azure Functions Core Tools
Core Tools Version:       4.0.6610 Commit hash: N/A +0d55b5d7efe83d85d2b5c6e0b0a9c1b213e96256 (64-bit)
Function Runtime Version: 4.1036.1.23224

[2025-01-14T00:56:41.615Z] Found H:\Develop\Samples\FunctionAppCancel\FunctionAppCancel\FunctionAppCancel.csproj. Using for user secrets file configuration.
[2025-01-14T00:56:43.806Z] Azure Functions .NET Worker (PID: 107448) initialized in debug mode. Waiting for debugger to attach...
[2025-01-14T00:56:43.841Z] Worker process started and initialized.

Functions:

        Function1: [GET,POST] http://localhost:7193/api/Function1

For detailed output, run func with --verbose flag.
[2025-01-14T00:56:48.886Z] Host lock lease acquired by instance ID '0000000000000000000000001BD189B9'.
[2025-01-14T00:56:52.633Z] Executing 'Functions.Function1' (Reason='This function was programmatically called via the host APIs.', Id=c0813456-e99e-4828-8b43-c2c6b28c97e6)
[2025-01-14T00:56:52.894Z] C# HTTP trigger function processed a request.
[2025-01-14T00:56:54.987Z] C# HTTP trigger function threw exception A task was canceled.
[2025-01-14T00:56:55.036Z] Function 'Function1', Invocation id 'c0813456-e99e-4828-8b43-c2c6b28c97e6': An exception was thrown by the invocation.
[2025-01-14T00:56:55.037Z] Result: Function 'Function1', Invocation id 'c0813456-e99e-4828-8b43-c2c6b28c97e6': An exception was thrown by the invocation.
Exception: System.ObjectDisposedException: Request has finished and HttpContext disposed.
[2025-01-14T00:56:55.038Z] Object name: 'HttpContext'.
[2025-01-14T00:56:55.039Z]    at Microsoft.AspNetCore.Http.DefaultHttpContext.ThrowContextDisposed()
[2025-01-14T00:56:55.040Z]    at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Features()
[2025-01-14T00:56:55.041Z]    at Microsoft.AspNetCore.Routing.RoutingHttpContextExtensions.GetRouteData(HttpContext httpContext)
[2025-01-14T00:56:55.042Z]    at Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.FunctionsHttpProxyingMiddleware.TryHandleHttpResult(Object result, FunctionContext context, HttpContext httpContext, Boolean isInvocationResult) in D:\a\_work\1\s\extensions\Worker.Extensions.Http.AspNetCore\src\FunctionsMiddleware\FunctionsHttpProxyingMiddleware.cs:line 77
[2025-01-14T00:56:55.043Z]    at Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.FunctionsHttpProxyingMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\extensions\Worker.Extensions.Http.AspNetCore\src\FunctionsMiddleware\FunctionsHttpProxyingMiddleware.cs:line 56
[2025-01-14T00:56:55.044Z]    at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 96
Stack:    at Microsoft.AspNetCore.Http.DefaultHttpContext.ThrowContextDisposed()
[2025-01-14T00:56:55.045Z]    at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Features()
[2025-01-14T00:56:55.046Z]    at Microsoft.AspNetCore.Routing.RoutingHttpContextExtensions.GetRouteData(HttpContext httpContext)
[2025-01-14T00:56:55.046Z]    at Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.FunctionsHttpProxyingMiddleware.TryHandleHttpResult(Object result, FunctionContext context, HttpContext httpContext, Boolean isInvocationResult) in D:\a\_work\1\s\extensions\Worker.Extensions.Http.AspNetCore\src\FunctionsMiddleware\FunctionsHttpProxyingMiddleware.cs:line 77
[2025-01-14T00:56:55.047Z]    at Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.FunctionsHttpProxyingMiddleware.Invoke(FunctionContext context, FunctionExecutionDelegate next) in D:\a\_work\1\s\extensions\Worker.Extensions.Http.AspNetCore\src\FunctionsMiddleware\FunctionsHttpProxyingMiddleware.cs:line 56
[2025-01-14T00:56:55.048Z]    at Microsoft.Azure.Functions.Worker.FunctionsApplication.InvokeFunctionAsync(FunctionContext context) in D:\a\_work\1\s\src\DotNetWorker.Core\FunctionsApplication.cs:line 96.
[2025-01-14T00:56:55.070Z] Executed 'Functions.Function1' (Failed, Id=c0813456-e99e-4828-8b43-c2c6b28c97e6, Duration=2463ms)
[2025-01-14T00:56:55.071Z] System.Private.CoreLib: Exception while executing function: Functions.Function1. Microsoft.Azure.WebJobs.Script.Grpc: Failed to proxy request with ForwarderError: RequestCanceled. System.Net.Http: The operation was canceled. System.Net.Sockets: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request.. The I/O operation has been aborted because of either a thread exit or an application request.
@jviau
Copy link
Contributor

jviau commented Jan 21, 2025

@liliankasem would the recent client disconnect changes improve this scenario?

@liliankasem
Copy link
Member

Yes, this is the known bug we are working to fix - it will be resolved when these two PRs are released:

I am going to close this issue as a duplicate as we have issues tracking the host and worker fixes (refer to GH issue numbers in the PR)

@david-maw
Copy link
Author

Thanks @liliankasem, I couldn't find an issue for this problem but didn't look for a PR, I'm glad it didn't turn out to be me misunderstanding how it ought to work.

Thans for the ETAs, do they apply to the production functions support code in Azure, or the local emulated environment run by VS, or both?

@liliankasem
Copy link
Member

@david-maw - no problem! One of the issues is in the dotnet worker so that might be how you missed it? (issue)

Re ETAs: this is for both; however, Core tools can't be released until the Host is released to Azure, so actually the local environment fix will be out after the production fix.

It's also worth noting that fix going into the dotnet worker can be used right away by upgrading the nuget package for the AspNet Http extension (when it is published), so half the issue is fixed there (the HttpContext disposed issue). The second half of the problem (Failed to proxy request with ForwarderError: RequestCanceled.) will be fixed when the host is released.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants