Map ParentId to MT-Activity-Id in MassTransit interop mode#2373
Merged
jeremydmiller merged 3 commits intoJasperFx:mainfrom Mar 30, 2026
Merged
Conversation
added 3 commits
March 30, 2026 11:47
When UseMassTransitInterop() is enabled, Wolverine writes trace context as `parent-id` in transport headers but MassTransit expects `MT-Activity-Id`. This breaks distributed trace propagation across the two frameworks. Remap the ParentId property to use MassTransit's `MT-Activity-Id` header key when interop mode is active, matching what InteropWithMassTransit already does for MessageType and ResponseAddress.
The SQS/SNS transports use standalone MassTransitMapper classes that bypass EnvelopeMapper entirely, so the ParentId → MT-Activity-Id header remapping does not apply to them. - SQS/SNS MassTransitMapper: write ParentId as MT-Activity-Id in outgoing MessageAttributes and read it back on incoming messages - MassTransitEnvelope: include ParentId in envelope body headers (outgoing) and restore it from body headers (incoming) as a fallback for any transport - AssemblyAttributes: add InternalsVisibleTo for Wolverine.AmazonSns so it can reference MassTransitHeaders
The trace context is already propagated at the transport level: - ASB/RabbitMQ via EnvelopeMapper (ApplicationProperties/AMQP headers) - SQS/SNS via MassTransitMapper (MessageAttributes) The envelope body changes were redundant with those, and the incoming side ran too late (after Activity creation) to be effective anyway.
This was referenced Mar 30, 2026
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
When
UseMassTransitInterop()is enabled on an endpoint, distributed traces break across Wolverine ↔ MassTransit because the two frameworks use different header keys for W3C trace context propagation:parent-idMT-Activity-IdInteropWithMassTransit()already remapsMessageType→MT-MessageTypeandReplyUri→MT-Response-Address, but it does not remapParentId→MT-Activity-Id. Both directions start a new root trace instead of continuing the caller's trace.Fix
ASB / RabbitMQ (via
EnvelopeMapper)Add one line to
InteropWithMassTransit()inEnvelopeMapper.cs:This replaces the default
parent-idmapping withMT-Activity-Idwhen interop mode is active — the same pattern already used forMessageType.SQS / SNS (standalone
MassTransitMapper)The SQS and SNS transports use standalone
MassTransitMapperclasses that bypassEnvelopeMapperentirely. Trace context is propagated via MessageAttributes instead:Envelope.ParentIdas anMT-Activity-IdMessageAttributeMT-Activity-IdMessageAttribute intoEnvelope.ParentIdAlso added
InternalsVisibleTo("Wolverine.AmazonSns")so the SNS transport can accessMassTransitHeaders.How it works
Envelope.ParentIdis written asMT-Activity-Idin transport headers/attributes. MassTransit'sGetParentActivityContext()reads it and continues the trace.MT-Activity-Idis read from transport headers/attributes intoEnvelope.ParentId. Wolverine'sWolverineTracing.StartEnvelopeActivity()usesParentIdto create the Activity with the correct parent span.Envelope.ParentIdis already persisted through the PostgreSQL outbox, so the mapped value survives the outbox round-trip.Files changed
MassTransitHeaders.csActivityId = "MT-Activity-Id"constantEnvelopeMapper.csParentIdtoMT-Activity-IdinInteropWithMassTransit()AssemblyAttributes.csInternalsVisibleTo("Wolverine.AmazonSns")Wolverine.AmazonSqs/Internal/MassTransitMapper.csMT-Activity-Idvia SQS MessageAttributesWolverine.AmazonSns/Internal/MassTransitMapper.csMT-Activity-Idvia SNS MessageAttributesVerified
Tested end-to-end with a .NET 10 Aspire PoC using both frameworks over Azure Service Bus (emulator). Before the fix, each side started independent traces. After the fix, all four use cases (event publish, command send, in both directions) produce a single connected trace visible in the Aspire dashboard.
Test plan
MassTransitEnvelopeTestspass (7/7 on net9.0 and net10.0)Wolverine.csproj,Wolverine.AzureServiceBus.csproj,Wolverine.AmazonSqs.csproj,Wolverine.AmazonSns.csprojall build cleanlyEnvelopeMapper.InteropWithMassTransitcode path)MassTransitMapper, now with attribute propagation)