Skip to content

Commit 2662628

Browse files
authored
Ensuring non http invocation responses are not processed by IHttpProxyService (#9984) (#10085)
* Fixing bug where non http invocation responses were going through IHttpProxyService.EnsureSuccessfulForwardingAsync * Test cleanup * Release notes and patch version bump.
1 parent 2462997 commit 2662628

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

release_notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<!-- Please add your release notes in the following format:
44
- My change description (#PR)
55
-->
6+
- Fixed a bug where non HTTP invocation responses were processed by `IHttpProxyService` when HTTP proxying capability is enabled (#9984)
67
- Update Python Worker Version to [4.28.1](https://github.com/Azure/azure-functions-python-worker/releases/tag/4.28.1)
78
- Fixed an issue causing sporadic HTTP request failures when worker listeners were not fully initialized on first request #9954
89
- Update Node.js Worker Version to [3.10.0](https://github.com/Azure/azure-functions-nodejs-worker/releases/tag/v3.10.0) (#9999)

src/WebJobs.Script.Grpc/Channel/GrpcWorkerChannel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ internal async Task InvokeResponse(InvocationResponse invokeResponse)
10941094

10951095
try
10961096
{
1097-
if (IsHttpProxyingWorker)
1097+
if (IsHttpProxyingWorker && context.FunctionMetadata.IsHttpTriggerFunction())
10981098
{
10991099
await _httpProxyService.EnsureSuccessfulForwardingAsync(context);
11001100
}

test/WebJobs.Script.Tests/Workers/Rpc/GrpcWorkerChannelTests.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,6 +1396,35 @@ public async Task GetFunctionMetadata_MultipleCalls_ReturnSameTask()
13961396
Assert.Same(functionsTask1, functionsTask2);
13971397
}
13981398

1399+
[Fact]
1400+
public async Task Ensure_SuccessfulForwardingAsync_Is_Invoked_OnlyFor_HttpInvocationResponses()
1401+
{
1402+
await CreateDefaultWorkerChannel(capabilities: new Dictionary<string, string>() { { RpcWorkerConstants.HttpUri, "http://localhost:1234" } });
1403+
1404+
var httpInvocationId = Guid.NewGuid();
1405+
ScriptInvocationContext httpInvocationContext = GetTestScriptInvocationContext(httpInvocationId, new TaskCompletionSource<ScriptInvocationResult>(), logger: _logger);
1406+
httpInvocationContext.FunctionMetadata = BuildFunctionMetadataForHttpTrigger("httpTrigger");
1407+
1408+
var timerInvocationId = Guid.NewGuid();
1409+
ScriptInvocationContext timerInvocationContext = GetTestScriptInvocationContext(timerInvocationId, new TaskCompletionSource<ScriptInvocationResult>(), logger: _logger);
1410+
timerInvocationContext.FunctionMetadata = BuildFunctionMetadataForTimerTrigger("timerTrigger");
1411+
1412+
// Send http trigger and timer trigger invocation invocation requests.
1413+
await _workerChannel.SendInvocationRequest(httpInvocationContext);
1414+
await _workerChannel.SendInvocationRequest(timerInvocationContext);
1415+
1416+
// Send http trigger and timer trigger invocation responses.
1417+
await _workerChannel.InvokeResponse(BuildSuccessfulInvocationResponse(timerInvocationId.ToString()));
1418+
await _workerChannel.InvokeResponse(BuildSuccessfulInvocationResponse(httpInvocationId.ToString()));
1419+
1420+
var logs = _logger.GetLogMessages().ToArray();
1421+
Assert.Single(logs.Where(m => m.FormattedMessage.Contains($"InvocationResponse received for invocation: '{timerInvocationId}'")));
1422+
Assert.Single(logs.Where(m => m.FormattedMessage.Contains($"InvocationResponse received for invocation: '{httpInvocationId}'")));
1423+
1424+
// IHttpProxyService.EnsureSuccessfulForwardingAsync method should be invoked only for http invocation response.
1425+
_mockHttpProxyService.Verify(m => m.EnsureSuccessfulForwardingAsync(It.IsAny<ScriptInvocationContext>()), Times.Once);
1426+
}
1427+
13991428
[Fact]
14001429
public async Task Log_And_InvocationResult_OrderedCorrectly()
14011430
{
@@ -1574,5 +1603,49 @@ private Task CreateSharedMemoryEnabledWorkerChannel(bool setEnvironmentVariable
15741603
// Send worker init request and enable the capabilities
15751604
return CreateDefaultWorkerChannel(capabilities: capabilities);
15761605
}
1606+
1607+
private static InvocationResponse BuildSuccessfulInvocationResponse(string invocationId)
1608+
{
1609+
return new InvocationResponse
1610+
{
1611+
InvocationId = invocationId,
1612+
Result = new StatusResult
1613+
{
1614+
Status = StatusResult.Types.Status.Success
1615+
},
1616+
};
1617+
}
1618+
1619+
private static FunctionMetadata BuildFunctionMetadataForHttpTrigger(string name, string language = null)
1620+
{
1621+
var functionMetadata = new FunctionMetadata() { Name = name, Language = language };
1622+
functionMetadata.Bindings.Add(new BindingMetadata()
1623+
{
1624+
Type = "httpTrigger",
1625+
Direction = BindingDirection.In,
1626+
Name = "req"
1627+
});
1628+
functionMetadata.Bindings.Add(new BindingMetadata()
1629+
{
1630+
Type = "http",
1631+
Direction = BindingDirection.Out,
1632+
Name = "$return"
1633+
});
1634+
1635+
return functionMetadata;
1636+
}
1637+
1638+
private static FunctionMetadata BuildFunctionMetadataForTimerTrigger(string name, string language = null)
1639+
{
1640+
var functionMetadata = new FunctionMetadata() { Name = name, Language = language };
1641+
functionMetadata.Bindings.Add(new BindingMetadata()
1642+
{
1643+
Type = "timerTrigger",
1644+
Direction = BindingDirection.In,
1645+
Name = "myTimer"
1646+
});
1647+
1648+
return functionMetadata;
1649+
}
15771650
}
15781651
}

0 commit comments

Comments
 (0)