Developing with the Azure Service Bus Emulator

For years, developers working with Azure Service Bus have longed for a local emulator to streamline development and testing. Relying on cloud-based instances for every iteration was costly, time-consuming, and often impractical. But as of November 19, 2024, Microsoft has answered those prayers with the official release of the Azure Service Bus Local Emulator!

Azure Service Bus Emulator is not a full replacement for Azure Service bus but is aimed at local development and testing never the less lets look into how to the features it offers and how to use it.

Getting Started with the emulator

Using the Service Bus emulator is simple:

  1. Create a Config file.
  2. Run the docker Compose file
  3. Connect.

Config File

The Config.json is the only way to configure the Service bus emulator, I have created a nuget package and supporting documentation to allow for programmatic creation of the file as follows:

Install the configuration builder package

dotnet add package ReardonTech.AzureServiceBusEmulator.Configuration

Then run the following example

var asbEmulatorConfig = AsbEmulatorConfigurationBuilder.WithNamespace("local", nOptions => 
    nOptions.WithQueue("Queue1")
        .WithQueue("Queue2")
        .WithTopic("Topic1", tOptions =>
            tOptions.WithSubscription("Subscription1")
                .WithSubscription("Subscription2"))
    ).Build();

File.WriteAllText("Config.json", JsonSerializer.Serialize(asbEmulatorConfig));

Config.json

{
  "UserConfig" : {
    "Namespaces" : [ {
      "Name" : "local",
      "Queues" : [ {
        "Name" : "Queue1",
        "Properties" : {
          "DeadLetteringOnMessageExpiration" : false,
          "DefaultMessageTimeToLive" : "PT1H",
          "DuplicateDetectionHistoryTimeWindow" : "PT20S",
          "ForwardDeadLetteredMessagesTo" : "",
          "ForwardTo" : "",
          "LockDuration" : "PT1M",
          "MaxDeliveryCount" : 3,
          "RequiresDuplicateDetection" : false,
          "RequiresSession" : false
        }
      }, {
        "Name" : "Queue2",
        "Properties" : {
          "DeadLetteringOnMessageExpiration" : false,
          "DefaultMessageTimeToLive" : "PT1H",
          "DuplicateDetectionHistoryTimeWindow" : "PT20S",
          "ForwardDeadLetteredMessagesTo" : "",
          "ForwardTo" : "",
          "LockDuration" : "PT1M",
          "MaxDeliveryCount" : 3,
          "RequiresDuplicateDetection" : false,
          "RequiresSession" : false
        }
      } ],
      "Topics" : [ {
        "Name" : "Topic1",
        "Properties" : {
          "DefaultMessageTimeToLive" : "PT1H",
          "DuplicateDetectionHistoryTimeWindow" : "PT20S",
          "RequiresDuplicateDetection" : false
        },
        "Subscriptions" : [ {
          "Name" : "Subscription1",
          "Properties" : {
            "DeadLetteringOnMessageExpiration" : false,
            "DefaultMessageTimeToLive" : "PT1H",
            "DuplicateDetectionHistoryTimeWindow" : "PT20S",
            "ForwardDeadLetteredMessagesTo" : "",
            "ForwardTo" : "",
            "LockDuration" : "PT1M",
            "MaxDeliveryCount" : 3,
            "RequiresDuplicateDetection" : false,
            "RequiresSession" : false
          },
          "Rules" : [ ]
        }, {
          "Name" : "Subscription2",
          "Properties" : {
            "DeadLetteringOnMessageExpiration" : false,
            "DefaultMessageTimeToLive" : "PT1H",
            "DuplicateDetectionHistoryTimeWindow" : "PT20S",
            "ForwardDeadLetteredMessagesTo" : "",
            "ForwardTo" : "",
            "LockDuration" : "PT1M",
            "MaxDeliveryCount" : 3,
            "RequiresDuplicateDetection" : false,
            "RequiresSession" : false
          },
          "Rules" : [ ]
        } ]
      } ]
    } ],
    "Logging" : {
      "Type" : "File"
    }
  }
}

Docker Compose

The easiest way to run the docker compose, once you have the configuration file above is to create a .env file and then run docker compose.

docker-compose -f .\Docker-Compose.yml up -d

.env

# Environment file for user defined variables in docker-compose.yml

# 1. CONFIG_PATH: Path to Config.json file
CONFIG_PATH="./Config.json"

# 2. ACCEPT_EULA: Pass 'Y' to accept license terms for Azure SQL Edge and Azure Service Bus emulator.
ACCEPT_EULA="Y"

# 3. MSSQL_SA_PASSWORD to be filled by user as per policy : https://learn.microsoft.com/en-us/sql/relational-databases/security/strong-passwords?view=sql-server-linux-ver16 
SQL_PASSWORD: "Password123!"
Info
Please ensure that you set the CONFIG_PATH to he location of the Generated Config.json file. As we wont be exposing the sql Server outside of the docker network it is less important.

Docker Compose File

name: microsoft-azure-servicebus-emulator
services:
  emulator:
    container_name: "servicebus-emulator"
    image: mcr.microsoft.com/azure-messaging/servicebus-emulator:latest
    volumes:
      - "${CONFIG_PATH}:/ServiceBus_Emulator/ConfigFiles/Config.json"
    ports:
      - "5672:5672"
    environment:
      SQL_SERVER: sqledge
      MSSQL_SA_PASSWORD: "${SQL_PASSWORD}"  # Password should be same as what is set for SQL Edge  
      ACCEPT_EULA: ${ACCEPT_EULA}
    depends_on:
      - sqledge
    networks:
      sb-emulator:
        aliases:
          - "sb-emulator"
  sqledge:
        container_name: "sqledge"
        image: "mcr.microsoft.com/azure-sql-edge:latest"
        networks:
          sb-emulator:
            aliases:
              - "sqledge"
        environment:
          ACCEPT_EULA: ${ACCEPT_EULA}
          MSSQL_SA_PASSWORD: "${SQL_PASSWORD}" # To be filled by user as per policy : https://learn.microsoft.com/en-us/sql/relational-databases/security/strong-passwords?view=sql-server-linux-ver16 

networks:
  sb-emulator:
Info
This will map port 5672 into the container which is the default un-encrypted AMQP port.

Connection your Application

To connect your existing application up to the Service Bus Emulator update your connection string to the following:

Endpoint=sb://localhost;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;

Note

You do not have to change the SharedAccessKeyName or SharedAccessKey as they are ignored by the Emulator.

If you are mapping to a different port you change the address localhost:5677 (for port 5677)

var client =
    new ServiceBusClient(
        "Endpoint=sb://localhost;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;");

For working example please checkout my sample project here

Whats supported and features

  • Core Functionality : while not everything is supported, most core functionality is supported.
    • Queues and Topics
    • Subscriptions and Filters
    • Message sessions
    • Dead Letter queues
  • AMQP protocol : Ensure realistic behavior.
  • Dockerised for easy deployment and management : Works the same cross system without needing to install dependencies, also allows for easy clean up.
  • Actively maintained by Microsoft : Will be kept upt to date.

Key Features not supported

  • Management Interface : In most projects I have used over the years there has been some automated managed checks, usually to check if a Subscription or Topic exists and create it if it does not. These must be enabled when using Azure Service Bus Emulator as it does not support them and the Service Bus Admin client will throw an error as the emulator is not listening on port 443.
  • Large Message Handling : Messages above 256kb are not supported, Queues or Topics may not exceed 100mb.
  • Maximum messaging entities : there is a maximum of 50 Queues or Topics allowable in any one Namespace, as well as a Maximum of 50 Subscriptions in a Topic.
  • UI Portal : There is not UI portal or visual metrics, all configuration must be done via the Config file.
  • Partitioned Entities : Partitioned Entities are not supported.
  • Azure Specific Integration : AzureAD, vNet Integration, Activity Logs, and the likes are not supported.
  • Auto scaling : Resources will not scale, and Geo-Disaster recovery is also not supported.

Conclusion

The release of the Azure Service Bus Local Emulator marks a significant step forward in simplifying and accelerating development with Azure Service Bus. By providing a robust and accessible local development environment, Microsoft has empowered developers to build and test messaging solutions with greater speed, efficiency, and cost-effectiveness.

Whether you’re a seasoned Azure developer or just starting your journey with Service Bus, the emulator is an invaluable tool to add to your arsenal. Dive in, explore its capabilities, and experience the benefits of local development firsthand. And don’t forget to contribute your feedback to the project’s GitHub repository to help shape its future development!