Multiplexed shared-topic filter support for the default topology#1399
Draft
danielmarbach wants to merge 33 commits into
Draft
Multiplexed shared-topic filter support for the default topology#1399danielmarbach wants to merge 33 commits into
danielmarbach wants to merge 33 commits into
Conversation
706c88e to
ce079f4
Compare
Replace separate publish and subscription modes with TopicRoutingMode, add fallback topic routing for unmapped events, and update verification coverage for the new topology behavior.
Treat the catch-all subscription family as compatible with correlation-filter rules on the same topic because Azure Service Bus evaluates subscription rules with OR semantics.
Describe the concrete publish, subscribe, unsubscribe, and topology-resolution behavior for each TopicRoutingMode value so the differences between Default, CatchAll, and NotMultiplexed are explicit.
Document that configuring a fallback topic routes otherwise-unmapped events and suppresses ThrowIfUnmappedEventTypes for those resolved cases.
…ould select Minor cleanup of the surrounding tests
Co-authored-by: Szymon Pobiega <szymon.pobiega@gmail.com>
Previously, a mapped event whose publish destination equaled FallbackTopic.TopicName but had no explicit RoutingOptions resolved to NotMultiplexed, while the subscriber-side equivalent resolved to FallbackTopic.Mode via the unmapped-event fallback. The two sides disagreed: the publisher would not stamp the correlation property, but the subscriber would provision a correlation filter rule. Messages silently failed to match. Make the resolution symmetric. On both sides, a null mode inherits FallbackTopic.Mode when the event/entry is unmapped OR when its topic equals FallbackTopic.TopicName. Explicit RoutingOptions.Mode or SubscriptionEntry.RoutingMode always wins. This makes the FallbackTopic configuration the pit of success for shared-topic routing: configuring a single fallback topic is enough to get matching publisher stamps and subscriber rules without requiring per-event type configuration.
The subscribe-side fallback mode inheritance compared the entry topic against FallbackTopic.TopicName after destinationManager.GetDestination had already prefixed the entry topic with the hierarchy namespace. The prefixed name never matched the raw fallback name, so the resolved mode silently fell back to NotMultiplexed under hierarchy. Resolve the routing mode from the raw entry topic in the Select callback, then apply the hierarchy prefix. Matches the publish-side resolution which also compares against the raw destination name.
The previous switch expression silently accepted any value via the default arm, including future enum members or unexpected runtime values. Use Enum.GetNames<TopicRoutingMode> to explicitly enumerate the valid set and reject anything else. This matches the validation intent of the removed TopicTopology.ValidateFallbackTopic.
The attribute reused the existing NSBASBEXP0004 shared with AzureServiceBusTopicsAttribute, so consumers who suppressed the topics warning also suppressed the fallback-mode warning. Allocate NSBASBEXP0006 for the fallback-mode attribute and add it to the NoWarn list in the csproj so the experimental attribute does not trigger a Release build failure.
The source-generated [AzureServiceBusTopics] attribute on FallbackTopicOptions.TopicName cannot see the parent TopologyOptions hierarchy namespace, so a 261-char topic name with a hierarchy prefix slips through. Re-run the same EntityValidator.ValidateTopics helper with the hierarchy options in scope from TopicTopology.Validate to close that gap, instead of duplicating the length/format regex.
…tributes and related classes
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.
Addresses:
This PR introduces multiplexed shared-topic filter support for Azure Service Bus while preserving the transport's recommended default model of topic-per-event.
The feature is intentionally designed for advanced scenarios where multiple event types need to share a topic, without forcing that complexity onto the default path. It adds first-class support for:
The result is a simpler and more extensible routing model that supports both deliberate topic sharing and pragmatic subscription ergonomics.
Design goals
The implementation keeps the default guidance unchanged:
This ensures the common case remains simple, while advanced topologies become easier to model.
High-level design
Unified routing model
Instead of separate publisher/subscriber mode systems, the PR consolidates behavior into a single routing concept:
TopicRoutingModeSupported modes:
NotMultiplexedCorrelationFilterSqlFilterThis reduces API surface area and removes the need for publisher/subscriber compatibility matrices.
Explicit opt-in shared-topic routing
Multiplexing is never accidental.
Users must explicitly choose shared-topic behavior through routing configuration. If they do nothing, existing topic-per-event behavior remains intact.
That keeps operational intent visible and avoids hidden coupling.
Fallback topic support for unmapped events
A new
FallbackTopicconcept allows unmapped event types to route through a shared topic.Events explicitly mapped to
FallbackTopic.TopicNamewithout a per-event routing mode inherit the fallback mode as well, keeping publisher stamping and subscriber rules symmetric across both regular and hierarchy-prefixed setups.This is particularly valuable for subscribers using:
Without requiring explicit mappings for every concrete event type.
That means teams can keep topic sharing deliberate while avoiding brittle per-event subscription maintenance.
Runtime behavior
CorrelationFilter mode
Publisher dispatch stamps normalized enclosed message types as boolean application properties.
Subscribers provision Azure Service Bus correlation rules that match exact type identities.
Benefits:
This makes correlation filters the preferred mode whenever possible.
SqlFilter mode
Uses SQL rules over
NServiceBus.EnclosedMessageTypes, preserving historical behavior and compatibility.Benefits:
Tradeoffs:
Validation changes
The implementation simplifies validation rules.
FallbackTopic.TopicNameandFallbackTopic.Modeare validated declaratively, so misconfigurations surface at startup rather than at first publish. A hierarchy-aware post-prefix length check catches names that exceed topic-name limits only after the prefix is applied.NotMultiplexedandCorrelationFiltercan coexist on the same topic/subscription because Azure Service Bus rules are OR-based. A catch-all rule already receives everything, making additional filtered rules redundant but harmless.SqlFilterremains distinct because it represents a different filtering strategy.Tradeoffs and intentional constraints
Why no custom filter override API?
This PR intentionally does not introduce a callback-based "bring your own filter" model.
That path creates a synchronization problem:
This reintroduces complexity the new unified design removes.
For advanced one-off scenarios, users can already use existing native message customization hooks.
Why CorrelationFilter over SqlFilter?
Correlation filters are preferred because they are:
SQL filters remain available for compatibility and scenarios correlation filters cannot express.
Future extensibility
This design deliberately leaves room for future enhancements without reshaping the public model.
SqlFilterPrecise
A stricter SQL matching mode that respects token boundaries instead of substring matching, avoiding accidental matches like:
OrderAcceptedOrderAcceptedV2TopicRoutingMode.Custom
A future advanced mode could allow custom publisher stamping and custom rule creation for the small percentage of highly specialized systems.
Because the current architecture centralizes dispatch stamping and subscription rule creation, such additions are feasible without redesigning the model.
Why this matters
This PR gives users the best of both worlds:
In short, it adds advanced topology flexibility without making the common case more complex.