Skip to content

Commit 006d6bb

Browse files
authored
Fix invocation timeout when incoming request contains "x-ms-invocation-id" header (#10980)
1 parent e04ccef commit 006d6bb

File tree

4 files changed

+93
-10
lines changed

4 files changed

+93
-10
lines changed

release_notes.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
### Release notes
2-
3-
<!-- Please add your release notes in the following format:
4-
- My change description (#PR)
5-
-->
6-
- Memory allocation optimizations in `ScriptStartupTypeLocator.GetExtensionsStartupTypesAsync` (#11012)
1+
### Release notes
2+
3+
<!-- Please add your release notes in the following format:
4+
- My change description (#PR)
5+
-->
6+
- Memory allocation optimizations in `ScriptStartupTypeLocator.GetExtensionsStartupTypesAsync` (#11012)
7+
- Fix invocation timeout when incoming request contains "x-ms-invocation-id" header (#10980)

src/WebJobs.Script.Grpc/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55

66
[assembly: InternalsVisibleTo("Microsoft.Azure.WebJobs.Script.Benchmarks")]
77
[assembly: InternalsVisibleTo("Microsoft.Azure.WebJobs.Script.Tests")]
8-
[assembly: InternalsVisibleTo("Microsoft.Azure.WebJobs.Script.Tests.Integration")]
8+
[assembly: InternalsVisibleTo("Microsoft.Azure.WebJobs.Script.Tests.Integration")]
9+
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

src/WebJobs.Script.Grpc/Server/DefaultHttpProxyService.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
5-
using System.Collections.Generic;
65
using System.Linq;
76
using System.Net.Http;
87
using System.Threading.Tasks;
@@ -96,8 +95,8 @@ public void StartForwarding(ScriptInvocationContext context, Uri httpUri)
9695
HttpContext httpContext = httpRequest.HttpContext;
9796
httpContext.Items[ScriptConstants.HttpProxyingEnabled] = bool.TrueString;
9897

99-
// add invocation id as correlation id
100-
httpRequest.Headers.TryAdd(ScriptConstants.HttpProxyCorrelationHeader, context.ExecutionContext.InvocationId.ToString());
98+
// add invocation id as correlation id, override existing header if present
99+
httpRequest.Headers[ScriptConstants.HttpProxyCorrelationHeader] = context.ExecutionContext.InvocationId.ToString();
101100

102101
var forwardingTask = _httpForwarder.SendAsync(httpContext, httpUri.ToString(), _messageInvoker, _forwarderRequestConfig).AsTask();
103102
context.Properties[ScriptConstants.HttpProxyTask] = forwardingTask;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.Azure.WebJobs.Script.Description;
9+
using Microsoft.Azure.WebJobs.Script.Grpc;
10+
using Microsoft.Extensions.Logging;
11+
using Moq;
12+
using Xunit;
13+
using Yarp.ReverseProxy.Forwarder;
14+
15+
namespace Microsoft.Azure.WebJobs.Script.Tests
16+
{
17+
public class DefaultHttpProxyServiceTests
18+
{
19+
private readonly Mock<IHttpForwarder> _httpForwarderMock;
20+
private readonly Mock<ILogger<DefaultHttpProxyService>> _loggerMock;
21+
private readonly DefaultHttpProxyService _proxyService;
22+
23+
public DefaultHttpProxyServiceTests()
24+
{
25+
_httpForwarderMock = new Mock<IHttpForwarder>();
26+
_loggerMock = new Mock<ILogger<DefaultHttpProxyService>>();
27+
_proxyService = new DefaultHttpProxyService(_httpForwarderMock.Object, _loggerMock.Object);
28+
}
29+
30+
[Fact]
31+
public void StartForwarding_SetsCorrelationHeader()
32+
{
33+
var httpContext = new DefaultHttpContext();
34+
httpContext.Items.Add(ScriptConstants.AzureFunctionsHttpTriggerContext, new());
35+
var invocationId = Guid.NewGuid();
36+
var context = new ScriptInvocationContext
37+
{
38+
FunctionMetadata = new FunctionMetadata { Name = "TestFunction" },
39+
ExecutionContext = new ExecutionContext { InvocationId = invocationId },
40+
Inputs = new List<(string Name, DataType Type, object Val)>
41+
{
42+
("req", DataType.String, httpContext.Request)
43+
},
44+
Properties = new Dictionary<string, object>()
45+
};
46+
47+
var httpUri = new Uri("http://localhost");
48+
49+
_proxyService.StartForwarding(context, httpUri);
50+
51+
var httpRequest = (HttpRequest)context.Inputs.First().Val;
52+
Assert.True(httpRequest.Headers.ContainsKey(ScriptConstants.HttpProxyCorrelationHeader));
53+
Assert.Equal(invocationId.ToString(), httpRequest.Headers[ScriptConstants.HttpProxyCorrelationHeader]);
54+
}
55+
56+
[Fact]
57+
public void StartForwarding_OverridesExistingCorrelationHeader()
58+
{
59+
var httpContext = new DefaultHttpContext();
60+
httpContext.Items.Add(ScriptConstants.AzureFunctionsHttpTriggerContext, new());
61+
var invocationId = Guid.NewGuid();
62+
var context = new ScriptInvocationContext
63+
{
64+
FunctionMetadata = new FunctionMetadata { Name = "TestFunction" },
65+
ExecutionContext = new ExecutionContext { InvocationId = invocationId },
66+
Inputs = new List<(string Name, DataType Type, object Val)>
67+
{
68+
("req", DataType.String, httpContext.Request)
69+
},
70+
Properties = new Dictionary<string, object>()
71+
};
72+
73+
var httpUri = new Uri("http://localhost");
74+
var existingCorrelationId = Guid.NewGuid().ToString();
75+
var httpRequest = (HttpRequest)context.Inputs.First().Val;
76+
httpRequest.Headers[ScriptConstants.HttpProxyCorrelationHeader] = existingCorrelationId;
77+
78+
_proxyService.StartForwarding(context, httpUri);
79+
Assert.Equal(invocationId.ToString(), httpRequest.Headers[ScriptConstants.HttpProxyCorrelationHeader]);
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)