do not wait for coordinator if not HttpTrigger (#1626)
This commit is contained in:
Родитель
3ab48709df
Коммит
f4c854ea7e
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -12,7 +14,10 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore
|
|||
{
|
||||
internal class FunctionsHttpProxyingMiddleware : IFunctionsWorkerMiddleware
|
||||
{
|
||||
private const string HttpTrigger = "httpTrigger";
|
||||
|
||||
private readonly IHttpCoordinator _coordinator;
|
||||
private readonly ConcurrentDictionary<string, bool> _isHttpTrigger = new();
|
||||
|
||||
public FunctionsHttpProxyingMiddleware(IHttpCoordinator httpCoordinator)
|
||||
{
|
||||
|
@ -21,9 +26,16 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore
|
|||
|
||||
public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
|
||||
{
|
||||
// Only use the coordinator for HttpTriggers
|
||||
if (!_isHttpTrigger.GetOrAdd(context.FunctionId, static (_, c) => IsHttpTriggerFunction(c), context))
|
||||
{
|
||||
await next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var invocationId = context.InvocationId;
|
||||
|
||||
// this call will block until the ASP.NET middleware pipleline has signaled that it's ready to run the function
|
||||
// this call will block until the ASP.NET middleware pipeline has signaled that it's ready to run the function
|
||||
var httpContext = await _coordinator.SetFunctionContextAsync(invocationId, context);
|
||||
|
||||
AddHttpContextToFunctionContext(context, httpContext);
|
||||
|
@ -45,5 +57,11 @@ namespace Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore
|
|||
{
|
||||
funcContext.Items.Add(Constants.HttpContextKey, httpContext);
|
||||
}
|
||||
|
||||
private static bool IsHttpTriggerFunction(FunctionContext funcContext)
|
||||
{
|
||||
return funcContext.FunctionDefinition.InputBindings
|
||||
.Any(p => p.Value.Type.Equals(HttpTrigger, System.StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,39 +14,65 @@ namespace Microsoft.Azure.Functions.Worker.Tests.AspNetCore
|
|||
{
|
||||
public class FunctionsHttpProxyingMiddlewareTests
|
||||
{
|
||||
private TestFunctionContext _functionContext;
|
||||
private HttpContext _httpContext;
|
||||
private Mock<IHttpCoordinator> _mockCoordinator;
|
||||
|
||||
|
||||
public FunctionsHttpProxyingMiddlewareTests()
|
||||
[Fact]
|
||||
public async Task Middleware_AddsHttpContextToFunctionContext_Success()
|
||||
{
|
||||
_functionContext = new TestFunctionContext(new TestFunctionDefinition(), new TestFunctionInvocation(), CancellationToken.None);
|
||||
_functionContext.Items = new Dictionary<object, object>();
|
||||
var test = SetupInputs("httpTrigger");
|
||||
var mockDelegate = new Mock<FunctionExecutionDelegate>();
|
||||
|
||||
_httpContext = new DefaultHttpContext();
|
||||
_httpContext.Request.Headers.Add(Constants.CorrelationHeader, _functionContext.InvocationId);
|
||||
var funcMiddleware = new FunctionsHttpProxyingMiddleware(test.MockCoordinator.Object);
|
||||
await funcMiddleware.Invoke(test.FunctionContext, mockDelegate.Object);
|
||||
|
||||
_mockCoordinator = new Mock<IHttpCoordinator>();
|
||||
_mockCoordinator
|
||||
.Setup(p => p.SetHttpContextAsync(_functionContext.InvocationId, _httpContext))
|
||||
.ReturnsAsync(_functionContext);
|
||||
_mockCoordinator
|
||||
.Setup(p => p.SetFunctionContextAsync(_functionContext.InvocationId, _functionContext))
|
||||
.ReturnsAsync(_httpContext);
|
||||
Assert.NotNull(test.FunctionContext.GetHttpContext());
|
||||
Assert.Equal(test.FunctionContext.GetHttpContext(), test.HttpContext);
|
||||
|
||||
mockDelegate.Verify(p => p.Invoke(test.FunctionContext), Times.Once());
|
||||
|
||||
test.MockCoordinator.Verify(p => p.SetFunctionContextAsync(It.IsAny<string>(), It.IsAny<FunctionContext>()), Times.Once());
|
||||
test.MockCoordinator.Verify(p => p.CompleteFunctionInvocation(It.IsAny<string>()), Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MiddlewareAddsHttpContextToFunctionContext_Sucess()
|
||||
public async Task Middleware_NoOpsOnNonHttpTriggers()
|
||||
{
|
||||
var funcMiddleware = new FunctionsHttpProxyingMiddleware(_mockCoordinator.Object);
|
||||
|
||||
var test = SetupInputs("someTrigger");
|
||||
var mockDelegate = new Mock<FunctionExecutionDelegate>();
|
||||
|
||||
await funcMiddleware.Invoke(_functionContext, mockDelegate.Object);
|
||||
var funcMiddleware = new FunctionsHttpProxyingMiddleware(test.MockCoordinator.Object);
|
||||
await funcMiddleware.Invoke(test.FunctionContext, mockDelegate.Object);
|
||||
|
||||
Assert.NotNull(_functionContext.GetHttpContext());
|
||||
Assert.Equal(_functionContext.GetHttpContext(), _httpContext);
|
||||
mockDelegate.Verify(p => p.Invoke(test.FunctionContext), Times.Once());
|
||||
|
||||
test.MockCoordinator.Verify(p => p.SetFunctionContextAsync(It.IsAny<string>(), It.IsAny<FunctionContext>()), Times.Never());
|
||||
test.MockCoordinator.Verify(p => p.CompleteFunctionInvocation(It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
|
||||
private static (FunctionContext FunctionContext, HttpContext HttpContext, Mock<IHttpCoordinator> MockCoordinator) SetupInputs(string triggerType)
|
||||
{
|
||||
var inputBindings = new Dictionary<string, BindingMetadata>()
|
||||
{
|
||||
{ "test", new TestBindingMetadata("test", triggerType, BindingDirection.In ) }
|
||||
};
|
||||
|
||||
var functionDef = new TestFunctionDefinition(inputBindings: inputBindings);
|
||||
|
||||
var functionContext = new TestFunctionContext(functionDef, new TestFunctionInvocation(), CancellationToken.None)
|
||||
{
|
||||
Items = new Dictionary<object, object>()
|
||||
};
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Request.Headers.Add(Constants.CorrelationHeader, functionContext.InvocationId);
|
||||
|
||||
var mockCoordinator = new Mock<IHttpCoordinator>();
|
||||
mockCoordinator
|
||||
.Setup(p => p.SetHttpContextAsync(functionContext.InvocationId, httpContext))
|
||||
.ReturnsAsync(functionContext);
|
||||
mockCoordinator
|
||||
.Setup(p => p.SetFunctionContextAsync(functionContext.InvocationId, functionContext))
|
||||
.ReturnsAsync(httpContext);
|
||||
|
||||
return new(functionContext, httpContext, mockCoordinator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче