fix(vertx-web): finish vertx.route-handler via RoutingContext.addEndHandler fallback#11312
Draft
zarirhamza wants to merge 1 commit intomasterfrom
Draft
fix(vertx-web): finish vertx.route-handler via RoutingContext.addEndHandler fallback#11312zarirhamza wants to merge 1 commit intomasterfrom
zarirhamza wants to merge 1 commit intomasterfrom
Conversation
…andler fallback Vert.x's `Http1xServerResponse.end(Buffer, PromiseInternal)` invokes the registered `endHandler` only when `closed == false` at the moment the response body has been written. In synthetic transports such as quarkus-amazon-lambda-rest's `VirtualClientConnection` (in-memory Netty channel) the writes and the connection close happen synchronously inside `responseComplete()`, so by the time the `!closed` guard runs `closed` is already `true` and `endHandler` is silently skipped. Symptom: `RouteHandlerWrapper` starts a `vertx.route-handler` span for every route in the chain (e.g. Quarkus's AuthenticationHandler) but `EndHandlerWrapper.handle` is never called, so the span is never finished. The span dies in PendingTrace and is not enqueued on the writer. All children parented to that span (`jakarta-rs.request`, `netty.client.request`, downstream `aws.http`/`aws.apigateway` inferred spans) end up orphaned in the trace UI. Fix: also register a finish via `RoutingContext.addEndHandler`, which fires on routing-context completion regardless of underlying connection state and on both success and failure. Both paths funnel through a shared idempotent `finishHandlerSpan` so the second one to fire on real-network transports is a no-op. Verified end-to-end against a Quarkus 3.15.4 / Java 21 Lambda chain (caller -> netty.client.request -> callee) on Datadog Lambda Extension v96. Pre-fix: 5/5 invocations Started, 0/5 Finished. Post-fix: 5/5 Started, 5/5 Finished, single connected trace tree in the UI. Refs: SLES-2837
Contributor
|
Hi! 👋 Thanks for your pull request! 🎉 To help us review it, please make sure to:
If you need help, please check our contributing guidelines. |
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.
Summary
In synthetic Vert.x transports — most importantly
quarkus-amazon-lambda-rest'sVirtualClientConnection(the in-memory Netty channel that AWS Lambda HTTP runtimes use) —Http1xServerResponse.end()synchronously closes the underlying connection, so by the time the inlinedif (!closed && endHandler != null)guard runs,closedistrueand the registeredendHandleris silently skipped.RouteHandlerWrapper.handle()relies onresponse().endHandler(...)to finish thevertx.route-handlerspan. When that hook never fires, the span is started but never finished, never enqueued on the writer, and silently dropped. Every child span parented to it (jakarta-rs.request,netty.client.request, downstreamaws.http/aws.apigatewayinferred spans) ends up orphaned in the trace UI.Fix
Also register a finish via
RoutingContext.addEndHandler(...), which fires on routing-context completion regardless of underlying connection state and on both success and failure. Both paths funnel through a shared idempotentRouteHandlerWrapper.finishHandlerSpan(routingContext)so the second one to fire on real-network transports is a no-op.Files touched:
RouteHandlerWrapper.java(+23/-0): register the fallback in the span-starter branch; addfinishHandlerSpanstatic helper.EndHandlerWrapper.java(-9/+1): delegate to the shared helper instead of duplicating the finish logic.Test plan
HttpServerResponsewhoseend()skips the user-registeredendHandler(mimicking the closed-connection path) and asserts the route-handler span is still finished viaaddEndHandler.caller -> netty.client.request -> callee) with Datadog Lambda Extension v96. Pre-fix: 5/5 invocations Started, 0/5 Finished. Post-fix: 5/5 Started, 5/5 Finished, single connected trace tree at the backend.Refs
SLES-2837