Skip to content

Commit efd0aef

Browse files
authored
[Bug Fix] ASP.NET pipeline hangs when function execution throws an unhandled exception (#2527)
1 parent ab70ee0 commit efd0aef

File tree

4 files changed

+35
-13
lines changed

4 files changed

+35
-13
lines changed

extensions/Worker.Extensions.Http.AspNetCore/release_notes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
- My change description (#PR/#issue)
55
-->
66

7-
### Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore <version>
7+
### Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore 1.3.2
88

9-
- <entry>
9+
- Fixes a bug where the invocation hangs when the function has an unhandled exception (#2527).

extensions/Worker.Extensions.Http.AspNetCore/src/FunctionsMiddleware/FunctionsHttpProxyingMiddleware.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,24 @@ public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next
4949
// Register additional context features
5050
context.Features.Set<IFromBodyConversionFeature>(FromBodyConversionFeature.Instance);
5151

52-
await next(context);
52+
try
53+
{
54+
await next(context);
55+
56+
var responseHandled = await TryHandleHttpResult(context.GetInvocationResult().Value, context, httpContext, true)
57+
|| await TryHandleOutputBindingsHttpResult(context, httpContext);
5358

54-
var responseHandled = await TryHandleHttpResult(context.GetInvocationResult().Value, context, httpContext, true)
55-
|| await TryHandleOutputBindingsHttpResult(context, httpContext);
56-
57-
if (!responseHandled)
59+
if (!responseHandled)
60+
{
61+
var logger = context.InstanceServices.GetRequiredService<ExtensionTrace>();
62+
logger.NoHttpResponseReturned(context.FunctionDefinition.Name, context.InvocationId);
63+
}
64+
}
65+
finally
5866
{
59-
var logger = context.InstanceServices.GetRequiredService<ExtensionTrace>();
60-
logger.NoHttpResponseReturned(context.FunctionDefinition.Name, context.InvocationId);
67+
// Allow ASP.NET Core middleware to continue
68+
_coordinator.CompleteFunctionInvocation(invocationId);
6169
}
62-
63-
// Allow ASP.NET Core middleware to continue
64-
_coordinator.CompleteFunctionInvocation(invocationId);
6570
}
6671

6772
private static async Task<bool> TryHandleHttpResult(object? result, FunctionContext context, HttpContext httpContext, bool isInvocationResult = false)

extensions/Worker.Extensions.Http.AspNetCore/src/Worker.Extensions.Http.AspNetCore.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<Description>ASP.NET Core extensions for .NET isolated functions</Description>
77

88
<!--Version information-->
9-
<VersionPrefix>1.3.1</VersionPrefix>
9+
<VersionPrefix>1.3.2</VersionPrefix>
1010
<TargetFramework>net6.0</TargetFramework>
1111
</PropertyGroup>
1212

test/DotNetWorkerTests/AspNetCore/FunctionsHttpProxyingMiddlewareTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Threading;
67
using System.Threading.Tasks;
@@ -259,5 +260,21 @@ private Mock<IResult> GetMockIResult()
259260

260261
return mockResult;
261262
}
263+
264+
[Fact]
265+
public async Task CompleteFunctionInvocation_RunsWhen_FunctionThrowsException()
266+
{
267+
var test = SetupTest("httpTrigger");
268+
var mockDelegate = new Mock<FunctionExecutionDelegate>();
269+
mockDelegate.Setup(d => d.Invoke(It.IsAny<FunctionContext>()))
270+
.Throws(new Exception("Custom exception message"));
271+
272+
var funcMiddleware = new FunctionsHttpProxyingMiddleware(test.MockCoordinator.Object);
273+
274+
await Assert.ThrowsAsync<Exception>(async () => await funcMiddleware.Invoke(test.FunctionContext, mockDelegate.Object));
275+
276+
mockDelegate.Verify(p => p.Invoke(test.FunctionContext), Times.Once());
277+
test.MockCoordinator.Verify(p => p.CompleteFunctionInvocation(It.IsAny<string>()), Times.Once());
278+
}
262279
}
263280
}

0 commit comments

Comments
 (0)