Skip to content

Commit 1bb6bd8

Browse files
authored
Fix error log in custom handler streaming for $return scenarios (#11262)
1 parent f8fcc65 commit 1bb6bd8

File tree

4 files changed

+60
-7
lines changed

4 files changed

+60
-7
lines changed

release_notes.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
- Moving to version 1.5.7 of Microsoft.Azure.AppService.Middleware.Functions (https://github.com/Azure/azure-functions-host/pull/11231)
99
- Refactor code to move the logic to search for WorkerConfigs to a default worker configuration resolver (#11219)
1010
- Update Node.js Worker Version to [3.11.0](https://github.com/Azure/azure-functions-nodejs-worker/releases/tag/v3.11.0)
11-
- Adding restart reason to the logs (#11191)
11+
- Adding restart reason to the logs (#11191)
12+
- Fix custom handler streaming bug where `$return` output binding scenarios result in error logs (#11262)

src/WebJobs.Script/Description/Workers/WorkerFunctionInvoker.cs

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

44
using System;
55
using System.Collections.Generic;
6+
using System.Collections.Immutable;
67
using System.Collections.ObjectModel;
78
using System.Diagnostics;
89
using System.IO;
@@ -211,6 +212,11 @@ private CancellationToken HandleCancellationTokenParameter(object input)
211212

212213
private void HandleReturnParameter(ScriptInvocationResult result)
213214
{
215+
if (result.Outputs is IImmutableDictionary<string, object> immutableOutputs)
216+
{
217+
return;
218+
}
219+
214220
result.Outputs[ScriptConstants.SystemReturnParameterBindingName] = result.Return;
215221
}
216222

src/WebJobs.Script/Workers/Http/DefaultHttpWorkerService.cs

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

44
using System;
@@ -101,6 +101,13 @@ internal async Task ProxyInvocationRequest(ScriptInvocationContext scriptInvocat
101101
_httpProxyService.StartForwarding(scriptInvocationContext, _destinationPrefix);
102102

103103
await _httpProxyService.EnsureSuccessfulForwardingAsync(scriptInvocationContext); // this will throw if forwarding is unsuccessful
104+
105+
// this needs to be removed to avoid downstream errors since the HttpResponse is already returned by proxying
106+
if (scriptInvocationContext.BindingData.Any(p => string.Equals(ScriptConstants.SystemReturnParameterBindingName, p.Key, StringComparison.OrdinalIgnoreCase)))
107+
{
108+
scriptInvocationContext.BindingData[ScriptConstants.SystemReturnParameterBindingName] = null;
109+
}
110+
104111
scriptInvocationContext.ResultSource.SetResult(ScriptInvocationResult.Success);
105112
}
106113
catch (Exception exc)

test/WebJobs.Script.Tests/Description/Worker/WorkerFunctionInvokerTests.cs

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

44
using System;
55
using System.Collections.ObjectModel;
6-
using System.Diagnostics.Metrics;
76
using System.Threading.Tasks;
87
using Microsoft.Azure.WebJobs.Script.Binding;
98
using Microsoft.Azure.WebJobs.Script.Description;
109
using Microsoft.Azure.WebJobs.Script.Metrics;
1110
using Microsoft.Azure.WebJobs.Script.Workers;
12-
using Microsoft.Extensions.Configuration;
1311
using Microsoft.Extensions.DependencyInjection;
1412
using Microsoft.Extensions.Hosting;
1513
using Microsoft.Extensions.Logging.Abstractions;
@@ -50,7 +48,9 @@ public WorkerFunctionInvokerTests()
5048
var sc = host.GetScriptHost();
5149

5250
FunctionMetadata metaData = new FunctionMetadata();
53-
_testFunctionInvoker = new TestWorkerFunctionInvoker(sc, null, metaData, NullLoggerFactory.Instance, null, new Collection<FunctionBinding>(),
51+
BindingMetadata bindingMetadata = new BindingMetadata();
52+
bindingMetadata.Name = "TestName";
53+
_testFunctionInvoker = new TestWorkerFunctionInvoker(sc, bindingMetadata, metaData, NullLoggerFactory.Instance, new Collection<FunctionBinding>(), new Collection<FunctionBinding>(),
5454
_mockFunctionInvocationDispatcher.Object, _applicationLifetime.Object, TimeSpan.FromSeconds(5));
5555
}
5656

@@ -104,5 +104,44 @@ public async Task InvokeInitialized_DoesNotCallShutdown()
104104
}
105105
_applicationLifetime.Verify(a => a.StopApplication(), Times.Never);
106106
}
107+
108+
[Fact]
109+
public async Task InvokeCore_DoesNotAddReturn_WhenOutputsIsImmutableDictionary()
110+
{
111+
// Arrange
112+
var mockBinder = new Mock<Binder>();
113+
var immutableOutputs = System.Collections.Immutable.ImmutableDictionary<string, object>.Empty;
114+
var invocationResult = new ScriptInvocationResult
115+
{
116+
Outputs = immutableOutputs,
117+
};
118+
119+
// Setup the dispatcher to complete the invocation with our result
120+
_mockFunctionInvocationDispatcher
121+
.Setup(d => d.InvokeAsync(It.IsAny<ScriptInvocationContext>()))
122+
.Callback<ScriptInvocationContext>(ctx =>
123+
{
124+
ctx.ResultSource.SetResult(invocationResult);
125+
})
126+
.Returns(Task.CompletedTask);
127+
128+
_mockFunctionInvocationDispatcher.Setup(a => a.State).Returns(FunctionInvocationDispatcherState.Initialized);
129+
130+
// Act
131+
var result = await _testFunctionInvoker.InvokeCore(
132+
new object[] { null, null, null, null, default(System.Threading.CancellationToken) },
133+
new FunctionInvocationContext
134+
{
135+
Binder = mockBinder.Object,
136+
ExecutionContext = new ExecutionContext
137+
{
138+
InvocationId = Guid.NewGuid()
139+
}
140+
});
141+
142+
// Assert
143+
Assert.IsType<System.Collections.Immutable.ImmutableDictionary<string, object>>(invocationResult.Outputs);
144+
Assert.False(invocationResult.Outputs.ContainsKey("$return"));
145+
}
107146
}
108147
}

0 commit comments

Comments
 (0)