Skip to content

Multiplexed shared-topic filter support for the default topology#1399

Draft
danielmarbach wants to merge 33 commits into
masterfrom
topology
Draft

Multiplexed shared-topic filter support for the default topology#1399
danielmarbach wants to merge 33 commits into
masterfrom
topology

Conversation

@danielmarbach
Copy link
Copy Markdown
Contributor

@danielmarbach danielmarbach commented Apr 22, 2026

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:

  • Explicit shared-topic routing
  • CorrelationFilter-based multiplexing
  • SqlFilter-based multiplexing
  • Fallback-topic based polymorphic subscriptions for unmapped event types

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:

  1. Prefer topic-per-event
  2. If multiplexing is required, prefer CorrelationFilter
  3. Use SqlFilter only when correlation filtering is insufficient

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:

TopicRoutingMode

Supported modes:

  • NotMultiplexed
  • CorrelationFilter
  • SqlFilter

This 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 FallbackTopic concept allows unmapped event types to route through a shared topic.

Events explicitly mapped to FallbackTopic.TopicName without 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:

  • base contracts
  • interfaces
  • polymorphic event hierarchies

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:

  • precise matching
  • fast native filtering
  • avoids string scanning
  • supports significantly higher rule counts than SQL filters
  • scales better for large multiplexed topologies

This makes correlation filters the preferred mode whenever possible.

SqlFilter mode

Uses SQL rules over NServiceBus.EnclosedMessageTypes, preserving historical behavior and compatibility.

Benefits:

  • leverages existing metadata
  • useful when correlation filters are insufficient
  • supports scenarios requiring expression-based matching

Tradeoffs:

  • lower rule-count limits than correlation filters
  • less precise than correlation filters
  • substring matching can overmatch similarly named types

Validation changes

The implementation simplifies validation rules.

FallbackTopic.TopicName and FallbackTopic.Mode are 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.

NotMultiplexed and CorrelationFilter can 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.

SqlFilter remains 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:

  • publishers must stamp exactly what subscribers expect
  • subscribers must define filters matching publisher conventions

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:

  • explicit
  • deterministic
  • contract-oriented
  • operationally efficient
  • able to scale to larger numbers of rules

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:

  • OrderAccepted
  • OrderAcceptedV2

TopicRoutingMode.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:

  • Keep topic-per-event as the recommended default
  • Support shared-topic routing when intentionally needed
  • Prefer the filter strategy that scales best operationally
  • Enable polymorphic subscription scenarios with less manual mapping
  • Keep the public API compact and understandable
  • Preserve room for future routing/filter innovations

In short, it adds advanced topology flexibility without making the common case more complex.

@danielmarbach danielmarbach changed the title Topology Multiplexed shared-topic filter support for the default topology Apr 22, 2026
Comment thread src/Transport/EventRouting/TopicRoutingMode.cs Outdated
Comment thread src/Transport/EventRouting/TopicRoutingMode.cs Outdated
Comment thread src/Transport/EventRouting/TopicRoutingMode.cs Outdated
danielmarbach and others added 16 commits June 2, 2026 10:55
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants