You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Added detailed documentation of the span parenting issue that occurs
with isolated Azure Functions using ASP.NET Core integration.
The issue: Worker process spans are incorrectly parented to the root
host span instead of the HTTP client span that makes the host-to-worker
call.
Documentation includes:
- Visual comparison of current vs expected span hierarchy
- Root cause analysis of context propagation flow
- Technical details about HTTP proxying and gRPC integration
- Step-by-step reproduction instructions
- Example code and API queries for verification
- Files that need to be modified for the fix
Copy file name to clipboardExpand all lines: docs/development/AzureFunctions.md
+76Lines changed: 76 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -95,6 +95,82 @@ Whether a Functions app uses this new mode is subtle:
95
95
96
96
and the project will have a reference to [Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore/) package.
97
97
98
+
## Known Issues and Fixes
99
+
100
+
### Span Parenting Issue with ASP.NET Core Integration (APMSVLS-58)
101
+
102
+
**Problem:**
103
+
When using isolated Azure Functions with ASP.NET Core Integration, spans created in the worker process are incorrectly parented to the root host span instead of the HTTP client span that makes the host→worker call.
104
+
105
+
**Current (Incorrect) Behavior:**
106
+
```
107
+
ROOT: azure_functions.invoke: GET /api/httptest [PID 27 - HOST]
108
+
├─ http.request: GET localhost:40521/api/HttpTest [HOST → WORKER HTTP call]
In `GrpcMessageConversionExtensionsToRpcHttpIntegration.cs`, the code injects the Azure Functions host span context into the gRPC message (line 87-88). However, when HTTP proxying is enabled with ASP.NET Core integration:
125
+
126
+
1. The host process creates an HTTP client call to the worker process (`GET localhost:40521/api/HttpTest`)
127
+
2. The HTTP client instrumentation automatically creates a span for this call
128
+
3. The HTTP client automatically propagates its trace context in the HTTP headers
129
+
4. However, the gRPC integration has already injected the *parent* span's context (the Azure Functions host span) into the gRPC message
130
+
5. The worker process extracts context from both sources, but prefers the gRPC context
131
+
6. This causes worker spans to be parented to the wrong span (the host root instead of the HTTP call)
132
+
133
+
**Technical Details:**
134
+
- When `isHttpProxying` is true, `func.exe` makes an actual HTTP call to the worker instead of only using gRPC
135
+
- The HTTP client span (e.g., `GET localhost:40521`) is created *after*`ToRpcHttp()` runs
136
+
- Currently, `ToRpcHttp()` injects the Azure Functions span context regardless of proxying mode
137
+
- The HTTP client instrumentation then injects its own context into HTTP headers
138
+
- The worker receives both contexts and needs to choose the correct one
139
+
140
+
**Solution:**
141
+
When HTTP proxying is enabled (`isHttpProxying && !requiresRouteParameters`), we should not inject trace context into the gRPC message. Instead, let the HTTP client instrumentation handle context propagation naturally through HTTP headers. This ensures worker spans are properly parented to the HTTP call span.
142
+
143
+
**How to Reproduce:**
144
+
1. Deploy an isolated Azure Functions app with ASP.NET Core integration
145
+
2. Create a function that makes an outbound HTTP call with a custom span:
0 commit comments