2
votes

I've been working through the eShopOnContainers project provided by Microsoft, honing my microservice skills in general. One of the big concepts is the introduction of an Event Bus. I've opted to try it with Azure Service Bus but my experience with the platform is limited.

I've managed to get the project running after manually creating the Topics, Subscriptions, etc, but this raises a few questions:

Is it not the responsibility of the subscribing application to create it's own Subscription in Azure? e.g. on startup?

Conceptually, Topics represent different event stacks, correct? E.g. Customers, Ordering, etc? Or are they intended to be domain event boundaries? E.g. in this application, 'eShop' would be the topic.

Azure deployments is a whole other topic, but related to the Service Bus configuration, are there any recommended techniques for managing that within source control?

Any insight is greatly appreciated.

2
I recommend u to have a look at Azure management fluent api github.com/Azure/azure-libraries-for-netMarcus Höglund
Ah, a potential missing link. I couldn't find the .NET Core varieties of this previously. Thank you.Jeremy Smith

2 Answers

2
votes

Is it not the responsibility of the subscribing application to create it's own Subscription in Azure? e.g. on startup?

That's correct. The details depend on the underlying messaging service you're using. In case of Azure Service Bus, each service upon startup will subscribe to the events it's interested in. For example, Ordering will subscribe during startup to the events it handles. The project has a IEventBusSubscriptionsManager contract to be implemented specifically for each messaging service. For Azure Service Bus implementation each service has a physical subscription and each event its interested in is represented by a rule, filtering messages by the value of Service Bus message Label (Label contains event name).

Conceptually, Topics represent different event stacks, correct? E.g. Customers, Ordering, etc? Or are they intended to be domain event boundaries? E.g. in this application, 'eShop' would be the topic

Topics are the points of fanning messages out. You could use a topic per service, but that would mean subscribers would need to know what service is publishing those events. Alternatively, and potentially better option is to have a topic that is known by all of your services, and publish events to that topic. Call it "Events" for now. Each service interested in various events would create a subscription. A subscription would be able to get any message (event) published to Events topic, but really should only "catch" and deliver events it needs (read "subscribed to"). That's where filtering is coming in. By creating filters (RuleDescriptions) a given subscription for each services declares on the broker what messages it will receive.

Azure deployments is a whole other topic, but related to the Service Bus configuration, are there any recommended techniques for managing that within source control?

A few options.

  1. Code-based creation of entities at at run-time (topics, subscriptions with rules, queues).
  2. Capture topology with ARM templates and version just like code in version control system.
  3. Use Azure CLI and version control your scripts.
2
votes

Based on the feedback, I was able to able to throw together a crude solution based on the eShop Event Bus to create the Azure Subscriptions upon startup:

 public EventBusServiceBus(IServiceBusPersisterConnection serviceBusPersisterConnection,
        ILogger<EventBusServiceBus> logger, IEventBusSubscriptionsManager subsManager, string subscriptionClientName,
        ILifetimeScope autofac, AzureUserCredentials userCredentials, string subscriptionId, string resourceGroupName, string serviceBusName, string topicName)
    {
        _serviceBusPersisterConnection = serviceBusPersisterConnection;
        _logger = logger;
        _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();

        _subscriptionClient = new Microsoft.Azure.ServiceBus.SubscriptionClient(serviceBusPersisterConnection.ServiceBusConnectionStringBuilder,
            subscriptionClientName);
        _autofac = autofac;

        var credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal(
          userCredentials.ClientId, userCredentials.ClientSecret, userCredentials.TenantId, AzureEnvironment.FromName(userCredentials.EnvironmentName));

        var azure = Azure
                .Configure()
                .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
                .Authenticate(credentials)
                .WithSubscription(subscriptionId);

        var nm = azure.ServiceBusNamespaces.GetByResourceGroup(resourceGroupName, serviceBusName);

        var topic = nm.Topics.GetByName(topicName);

        if (topic == null)
            throw new ArgumentException($"Topic {topic} does not exist.", nameof(topic));

        Microsoft.Azure.Management.ServiceBus.Fluent.ISubscription subscription = null;
        try
        { subscription = topic.Subscriptions.GetByName(subscriptionClientName); }
        catch { }

        if (subscription == null)
        {
            logger.LogInformation($"Creating Azure Subscription '{subscriptionClientName}'");
            topic.Subscriptions.Define(subscriptionClientName).WithDeleteOnIdleDurationInMinutes(5).Create();
        }
        else
        {
            logger.LogInformation($"Azure Subscription '{subscriptionClientName}' already exists. Reusing.");
        }

        RemoveDefaultRule();
        RegisterSubscriptionClientMessageHandler();
    }