fix(tracing): continue inbound W3C trace context at the ACP boundary - #490
Open
NiteshDhanpal wants to merge 1 commit into
Open
fix(tracing): continue inbound W3C trace context at the ACP boundary#490NiteshDhanpal wants to merge 1 commit into
NiteshDhanpal wants to merge 1 commit into
Conversation
Root cause of async trace detachment (proven via [TP-DEBUG] probes): the ingress traceparent arrives in the HTTP header (inbound=00-<trace>...) but FastACP never extracts it, so the app's active OTel context is <none>. Downstream the Temporal start_workflow/signal (incl. the asyncio.create_task background dispatch) fires with no active span, the interceptor injects nothing, and the workflow + every activity start FRESH traces disconnected from the ingress. Extract + attach the inbound W3C context in the ASGI RequestIDMiddleware (wraps the whole request, so the bg task inherits it via create_task's context copy). Now the interceptor propagates the ingress trace across the Temporal boundary and the workflow/activity inherit it -> one connected trace. Fail-open. Unit-tested. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| from opentelemetry import context as _otel_context | ||
| from opentelemetry.propagate import extract | ||
|
|
||
| carrier = {k.decode("latin-1"): v.decode("latin-1") for k, v in scope_headers} |
There was a problem hiding this comment.
Repeated propagation headers collapse
Converting the raw ASGI header list to a dictionary retains only the final value of repeated baggage or tracestate fields, silently omitting earlier propagation metadata from downstream context.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/sdk/fastacp/base/base_acp_server.py
Line: 69
Comment:
**Repeated propagation headers collapse**
Converting the raw ASGI header list to a dictionary retains only the final value of repeated `baggage` or `tracestate` fields, silently omitting earlier propagation metadata from downstream context.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #484.
Problem
After #484 (business↔obs correlation + Option A) and #485 (Temporal interceptor), an async turn's obs trace still detached from the ingress: the workflow + every activity started fresh traces, unlinked from the
event/sendAPI call.Root cause (proven on infra-staging with per-hop
traceparentprobes): the ingresstraceparentarrives at the agent's ACP server in the HTTP header, but FastACP never extracts it — the active OTel context stays empty. Sostart_workflow/signal(and theasyncio.create_taskbackground dispatch) fire with no active span, the Temporal interceptor injects nothing, and the workflow/activities root fresh traces.Fix
Extract + attach the inbound W3C context in the ASGI
RequestIDMiddleware, which wraps the whole request (so the background task inherits it viacreate_task's context copy). Now the interceptor propagates the ingress trace across the Temporal boundary and the workflow/activity inherit it → one connected trace. Fail-open (obs never breaks a request).Verified (infra-staging)
Trace
12c6290e…: 347 spans across all 4 services in one tree — gatewayPOST /agents/{id}/rpc→ agent ACP →RunWorkflow→HandleSignal:receive_event→RunActivity→ egp/identity/DB. Per-hop probes confirmedtraceparentwent from<none>→ the ingress trace at every hop (ACP + worker). (Requires the control-plane header-forward fix, scaleapi/scale-agentex#396, to deliver the header.)Tests
tests/test_trace_context_extraction.py— extract-makes-inbound-active, fail-open on missing header, safe detach.ruffclean.🤖 Generated with Claude Code
Greptile Summary
The PR extracts and attaches inbound W3C trace context around each FastACP HTTP request so Temporal dispatch created during the request inherits the ingress trace, then safely detaches the request context.
Confidence Score: 4/5
The PR appears safe to merge, with a non-blocking interoperability issue for repeated baggage or tracestate header fields.
The request-scoped attach/detach lifecycle supports the intended Temporal propagation path, while dictionary conversion can omit portions of valid multi-line W3C propagation metadata.
Files Needing Attention: src/agentex/lib/sdk/fastacp/base/base_acp_server.py
Important Files Changed
Sequence Diagram
sequenceDiagram participant Gateway participant Middleware as RequestIDMiddleware participant ACP as ACP Handler participant Temporal as Temporal Client participant Worker as Workflow/Activity Worker Gateway->>Middleware: HTTP request + traceparent Middleware->>Middleware: extract and attach context Middleware->>ACP: Handle JSON-RPC under ingress context ACP->>Temporal: Start workflow or signal Temporal->>Worker: Propagate trace context Worker-->>Worker: Continue ingress trace ACP-->>Middleware: Request handling returns Middleware->>Middleware: Detach contextPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "fix(tracing): continue inbound W3C trace..." | Re-trigger Greptile