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

'functionCompletionTask' is being set when already complete in Extensions.Http.AspNetCore #2413

Closed
liliankasem opened this issue Apr 18, 2024 · 0 comments · Fixed by #2414
Closed
Assignees
Labels
area: http Items related to experience improvements for HTTP triggers bug Something isn't working

Comments

@liliankasem
Copy link
Member

liliankasem commented Apr 18, 2024

Description

There appears to be a bug in Extensions.Http.AspNetCore during function completion. When a Http invocation gets cancelled, an InvalidOperationException is thrown instead of expected TaskCanceledException.

This occurs because during cancellation we cancel the CancellationTokenSource in the invocation handler:

This completes the _functionCompletionTask:

internal void SetCancellationToken(CancellationToken token)
{
_token = token;
_tokenRegistration = _token.Register(() =>
{
_functionStartTask.TrySetCanceled();
_functionCompletionTask.TrySetCanceled();
_functionContextValueSource.TrySetCanceled();
_httpContextValueSource.TrySetCanceled();
});
}

When CompleteFunction is called the _functionCompletionTask task is already complete, but we try to set the result here anyway:

internal void CompleteFunction()
{
if (_httpContextValueSource.Task.IsCompleted)
{
if (_httpContextValueSource.Task.IsCanceled || _token.IsCancellationRequested)
{
_functionCompletionTask.SetCanceled();
}

Which leads to the InvalidOperationException exception.

Exception: System.InvalidOperationException: An attempt was made to transition a task to a final state when it had already completed.

Repro

Repro can be found in this GH issue:

Fix

First we can implement a check at the start of CompleteFunction to see if the task is complete before trying to set a result i.e.

if (_functionCompletionTask.Task.IsCompleted)
{
    return;
}

This still leads to a different exception FunctionInvocationException with a TaskCanceledException inner exception.

Executed 'Functions.BlobStream' (Failed, Id=c4cb3e5e-a039-4a44-a4d2-172ac6be0668, Duration=25692ms)
      Microsoft.Azure.WebJobs.Host.FunctionInvocationException: Exception while executing function: Functions.BlobStream
       ---> System.InvalidOperationException: Failed to proxy request with ForwarderError: ResponseBodyCanceled
       ---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.
         at System.Net.Http.CancellationHelper.ThrowOperationCanceledException(Exception innerException, CancellationToken cancellationToken)
         at System.Net.Http.HttpConnection.ContentLengthReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
         at Yarp.ReverseProxy.Forwarder.StreamCopier.CopyAsync(Stream input, Stream output, Int64 promisedContentLength, StreamCopierTelemetry telemetry, ActivityCancellationTokenSource activityToken, Boolean autoFlush, CancellationToken cancellation)

If there are other enhancements to make here, they should be considered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: http Items related to experience improvements for HTTP triggers bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant