Repository navigation
Conversation
When an envelope is scheduled to a transport without native scheduled-send support (RabbitMQ, Kafka, SharedMemory, ...), MessageRoute wraps it via ForScheduledSend and the transport ultimately serializes the inner envelope. Previously context-derived fields (TenantId, SagaId, CorrelationId, UserName) were only stamped on the outer wrapper, so the inner lost them by the time it reached the receiving handler. Extracts a virtual StampEnvelope method on MessageBus containing the idempotent context-derived stamps and applies it to both the outer envelope and the inner envelope of a scheduled wrap. MessageContext overrides it to add SagaId. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Member
|
Hey, I'm going to want a little more review on this one, so it's not going to make the release this morning |
Contributor
Author
|
Should I put any effort in this to resolve the merge conflict? |
3 tasks done
Member
|
I took your test, but went a little different way to keep overhead out of the hot path: #2605 |
Contributor
Author
|
Great you fixed it, thnx! |
Merged
2 tasks done
jeremydmiller
added a commit
that referenced
this pull request
May 8, 2026
….CopyContextCorrelationFrom() Supersedes the implementation in #2709 while keeping the test contract Lyall established (cherry-picked here as the parent commit so attribution is preserved end-to-end). Behavioural shape is identical to Lyall's PR — re-routed envelopes inherit the inbound's correlation, tenant id, and distributed-trace parent — but the field copying is delegated to the existing `Envelope.CopyContextCorrelationFrom` helper. That method was added in GH-2571 / PR #2572 to give the durable scheduled-send unwrap path (`ScheduledSendEnvelopeHandler`) and the in-memory tracked-session replay path (`TrackedSession.ReplayAll`) one canonical place to copy the six context-correlation fields: CorrelationId, ConversationId, TenantId, UserName, ParentId, SagaId The global-partitioning re-route is the same forwarding shape — same logical message, different shard — so it should reuse the same helper rather than re-state the field list inline. This PR adds it as the third caller. Implementation: * `RouteBus` (private subclass of `MessageBus`) still seeds `Envelope = inbound` so `IEnvelopeRule.ApplyCorrelation` consumers like `PropagateHeadersRule` continue to see the originator and honour the `PropagateIncomingHeadersToOutgoing` allowlist. * `RouteBus` overrides `TrackEnvelopeCorrelation` and replaces the base bus's narrower per-field pull-from-bus logic with a single `outbound.CopyContextCorrelationFrom(_inbound)` call. The base copies `CorrelationId` / `TenantId` / `UserName` from the bus's own properties and writes a fresh `ParentId` from `Activity.Current` — both wrong for a forwarded envelope: `ConversationId` would restart, `SagaId` would drop, and the trace would re-root at the interceptor hop instead of continuing the inbound's parent. * The interceptor's `DeliveryOptions` is reduced to just `GroupId`, which is the only piece routing itself needs to read — every context field flows through the bus's overridden tracker. Test coverage: same suite, lifted from #2709 unchanged. The two `ShouldNotContainKey` calls were tweaked to disambiguate Shouldly's `IDictionary` / `IReadOnlyDictionary` overloads (`Envelope.Headers` is a concrete `Dictionary`); behavioural assertions are otherwise verbatim. Tests: full `Runtime.Partitioning` suite green (78/78) on net9.0, including the 16 GP-interceptor cases with the four new context behaviours from #2709. Co-Authored-By: Lyall Guiney <lyall@sportcontext.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Fixes #2571.
Summary
MessageRoute.ForScheduledSendwraps it and previously eagerly serialized the inner intoouter.DatabeforeTrackEnvelopeCorrelationcould stamp context fields. The inner therefore arrived on the receive side withTenantId = null,SagaId = null,CorrelationId/UserNameunset — breaking multi-tenanted saga timeouts and observability chains.EnvelopeReaderWriter.Write, which now unwrapsmodel.Messageto serialize the inner.MessageBus.StampEnvelopewith the idempotent context-derived stamps (Source,CorrelationId,TenantId,UserName);MessageContextoverrides it to addSagaId.TrackEnvelopeCorrelationcalls it on the outer and, when the envelope is a scheduled wrap, also on the inner.Test plan
CoreTests.Runtime.Scheduled.inner_envelope_is_stamped_before_serialization— in-process via SharedMemory wrap path; assertsTenantId,CorrelationId,UserNameon the delivered inner.Wolverine.RabbitMQ.Tests.scheduled_saga_timeout_preserves_tenant— end-to-end multi-tenant saga with Marten + RabbitMQ + durable outbox; verifies the handler runs under the original tenant and the saga completes.main, pass in isolation).