Serberuss
Serberuss

Reputation: 2387

Why does AzureServiceBusTransport keep creating a sql filter for only 1 event? (NServiceBus transport)

NServiceBus version: 7.5.0

.NET Version: 5

I have a .NET API where I have a number of handlers and an NServiceBus saga. This now includes commands and events. The commands aren't a problem and they work fine across multiple projects and handlers, and the events weren't an issue until I created more than 1.

I was originally using NServiceBus conventions so that I could define my own interfaces and I registered them with the application (where Shared.Interfaces.IEvent is my own interface):

conventions.DefiningEventsAs(type => typeof(Shared.Interfaces.IEvent).IsAssignableFrom(type));

I am using Azure Service Bus as the transport layer and so I have a simple configuration for that in my Program.cs file:

var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
transport.ConnectionString(options.TransportConnectionString)
         .SubscriptionRuleNamingConvention(t => LimitNumberCharactersTopicName(options.Prefix + options.TopicName))
         .TopicName(options.Prefix + options.TopicName);

This successfully creates a topic and I can verify that it has 3 subscriptions which is what I'd expect, since I have 3 projects using the service bus. To be clear EnableInstallers is enabled:

var endpointConfiguration = new EndpointConfiguration(options.Prefix + options.EndpointName);
endpointConfiguration.SendFailedMessagesTo(options.Prefix + "error");
endpointConfiguration.EnableInstallers();

However I've also noticed that I have 2 filters applied to one of my subscriptions:

Name Filter type Rule
$default SqlFilter 1=0
ComputerName.TopicName SqlFilter [NServiceBus.EnclosedMessageTypes] LIKE '%Services.Shared.InternalApi.OrderEvent%'

I understand that the first rule blocks all events and the second is supposed to allow through specific events, but the issue is there is more than 1 event which means that the OrderEvent can be handled without an issue, but the other one never gets handled.

At first I thought this might have been due to the way I was creating conventions so I changed it slightly:

conventions.DefiningEventsAs(type => type.Name == nameof(OrderEvent) || type.Name == typeof(PricedEvent));

However this didn't make any difference. I also noticed that if I changed the structure of the shared project slightly (alphabetically) the rule would change to describe the PricedEvent rather than the first one. This might not mean anything but I thought it was interesting.

I eventually changed this so that I didn't use conventions at all temporarily but instead used the IEvent interface that comes with NServiceBus. However, this didn't solve my problem either.

I've tried restructuring the project so that the events sit in the root of my project and share the same namespaces but this also hasn't helped. If I manually delete the filter from Azure it will be recreated again once I run the solution in Visual Studio.

Because I am using a saga in my project I thought perhaps the SqlPersistence may have been something to do with this issue so I temporarily got rid of it and ran the solution, but again this didn't seem to make a difference.

I've tried searching for this to see if anyone else had come across the same issue but I was unable to find anything that matched the problem I am seeing. At this point I am a bit stuck for what might be causing this rule for 1 event to be created.

I'd greatly appreciate any help with this.

Upvotes: 0

Views: 267

Answers (2)

Serberuss
Serberuss

Reputation: 2387

So after a bit more investigation I realised what the issue was. The LimitNumberCharactersTopicName as described in my post but that I didn't actually show the implementation for was causing problems. The actual method looked like this:

private static string LimitNumberCharactersTopicName(string topicName)
{
    const int maxNumberChars = 50;
    return topicName.Length > maxNumberChars ? topicName[maxNumberChars..] : topicName;
}

I instead replaced the SubscriptionRuleNamingConvention call with the same code that exists in the NServiceBus samples and it is not working as expected. So my setup now looks like the following:

SubscriptionRuleNamingConvention(x => x.ToString().Length > 50 ? x.ToString()[^50..] : x.ToString())

Upvotes: 0

Sean Feldman
Sean Feldman

Reputation: 25994

The way the Azure Service Bus transport works is creating a subscription per endpoint with a rule per event type the endpoint subscribes to. If the endpoint subscribes to one event, there will be two filters, no-op filter and the event filter. If the endpoint subscribes to N events, there will be N+1 filters, no-op filter and the N events filters. That ensures all the messages of the types the endpoint is subscribed to are collected by the subscription and forwarded to the endpoints’s input queue. This is known as the transport topology.

The no-op filter is there because the ASBSDK has to have a filter when a subscription is created and the transport doesn’t know at the point of subscriptions creation what events are going to be handled. So it adds the no-op event. It’s harmless and not worth trying to go and remove it. But if you want drop it for good, you’d have to switch to provisioning your topology using a scripting method instead of relying on NServiceBus installers. See operational scripting documentation for details.

Upvotes: 1

Related Questions