DEV Community

Daniel Jonathan
Daniel Jonathan

Posted on

Dockerizing Azure Service Bus Emulator and Test with Logic Apps

Run Azure Logic Apps Standard with Service Bus Emulator completely in Docker - zero Azure resources needed.

This guide covers:

  • 🐳 Complete Docker setup with memory optimization
  • πŸ”§ Logic Apps configuration for Service Bus
  • πŸ“¨ Queue and Topic messaging patterns
  • 🎯 SQL filters for message routing
  • βœ… Real working examples (wf4, wf5, wf6, wf7)

Why This Setup?

  • ⚑ Fast local development
  • πŸ’Έ Zero Azure costs
  • πŸ”Œ Works offline
  • πŸ§ͺ Safe testing environment
  • πŸ” Same behavior as Azure Service Bus
  • 🐳 Everything containerized

Prerequisites

Docker Memory Configuration

Critical: Service Bus Emulator requires significant memory.

Minimum Requirements:

  • Docker Desktop: 15-16GB RAM
  • Service Bus container: 8GB
  • SQL Server: 2GB

Configure Docker Desktop:

  1. Open Docker Desktop β†’ Settings β†’ Resources
  2. Set Memory to 15.6GB or higher
  3. Click Apply & Restart

Without sufficient memory, the Service Bus emulator will crash with Out of memory errors (exit code 133).


Project Structure

LADevStuff2/                      # Logic App project
β”œβ”€β”€ connections.json              # Service Bus connection config
β”œβ”€β”€ local.settings.json           # Connection strings
β”œβ”€β”€ wf4/
β”‚   └── workflow.json             # Queue receiver
β”œβ”€β”€ wf5/
β”‚   └── workflow.json             # Topic subscriber (TypeA filter)
β”œβ”€β”€ wf6/
β”‚   └── workflow.json             # Topic subscriber (TypeB filter)
└── wf7_sb_send/
    └── workflow.json             # Message sender

DockerFiles/
β”œβ”€β”€ docker-compose.yml            # Container orchestration
└── ServiceBus/
    β”œβ”€β”€ Config.json               # Queue, Topic, Filters
    └── .env                      # SQL Server credentials
Enter fullscreen mode Exit fullscreen mode

Step 1: Service Bus Configuration

DockerFiles/ServiceBus/Config.json

This defines your Service Bus entities with SQL filters:

{
  "UserConfig": {
    "Namespaces": [
      {
        "Name": "sbemulatorns",
        "Queues": [
          {
            "Name": "local-orders-queue",
            "Properties": {
              "DeadLetteringOnMessageExpiration": false,
              "DefaultMessageTimeToLive": "PT1H",
              "LockDuration": "PT1M",
              "MaxDeliveryCount": 10,
              "RequiresDuplicateDetection": false,
              "RequiresSession": false
            }
          }
        ],
        "Topics": [
          {
            "Name": "local-orders-topic",
            "Properties": {
              "DefaultMessageTimeToLive": "PT1H",
              "RequiresDuplicateDetection": false
            },
            "Subscriptions": [
              {
                "Name": "local-orders-sub",
                "Properties": {
                  "DeadLetteringOnMessageExpiration": false,
                  "DefaultMessageTimeToLive": "PT1H",
                  "LockDuration": "PT1M",
                  "MaxDeliveryCount": 10,
                  "RequiresSession": false
                }
              },
              {
                "Name": "wf5-sub",
                "Properties": {
                  "DeadLetteringOnMessageExpiration": false,
                  "DefaultMessageTimeToLive": "PT1H",
                  "LockDuration": "PT1M",
                  "MaxDeliveryCount": 10,
                  "RequiresSession": false
                },
                "Rules": [
                  {
                    "Name": "TypeAFilter",
                    "Properties": {
                      "FilterType": "Sql",
                      "SqlFilter": {
                        "SqlExpression": "user.orderType = 'TypeA'"
                      }
                    }
                  }
                ]
              },
              {
                "Name": "wf6-sub",
                "Properties": {
                  "DeadLetteringOnMessageExpiration": false,
                  "DefaultMessageTimeToLive": "PT1H",
                  "LockDuration": "PT1M",
                  "MaxDeliveryCount": 10,
                  "RequiresSession": false
                },
                "Rules": [
                  {
                    "Name": "TypeBFilter",
                    "Properties": {
                      "FilterType": "Sql",
                      "SqlFilter": {
                        "SqlExpression": "user.orderType = 'TypeB'"
                      }
                    }
                  }
                ]
              }
            ]
          }
        ]
      }
    ],
    "Logging": {
      "Type": "File"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ SQL Filter Syntax: Use user.propertyName for custom properties in filters.

DockerFiles/ServiceBus/.env

ACCEPT_EULA=Y
MSSQL_SA_PASSWORD=StrongPassword123!
Enter fullscreen mode Exit fullscreen mode

Step 2: Docker Compose Setup

DockerFiles/docker-compose.yml

services:
  # Azure Storage Emulator
  azurite:
    image: mcr.microsoft.com/azure-storage/azurite
    container_name: azurite-shared
    ports:
      - "10000:10000" # Blob
      - "10001:10001" # Queue
      - "10002:10002" # Table
    networks:
      - shared-network

  # SQL Server 2022 (Service Bus backend)
  mssql:
    container_name: mssql-shared
    image: mcr.microsoft.com/mssql/server:2022-latest
    platform: linux/amd64
    env_file:
      - ./ServiceBus/.env
    mem_limit: 2g
    memswap_limit: 2g
    networks:
      - shared-network

  # Service Bus Emulator
  servicebus-emulator:
    container_name: servicebus-emulator-shared
    platform: linux/amd64
    image: mcr.microsoft.com/azure-messaging/servicebus-emulator:latest
    pull_policy: always
    depends_on:
      - mssql
    volumes:
      - ./ServiceBus/Config.json:/ServiceBus_Emulator/ConfigFiles/Config.json
    ports:
      - "5672:5672" # AMQP
      - "5300:5300" # Management
    env_file:
      - ./ServiceBus/.env
    environment:
      SQL_SERVER: mssql
      ACCEPT_EULA: Y
    mem_limit: 8g
    memswap_limit: 8g
    shm_size: 2g
    networks:
      - shared-network

  # Logic App Container
  logicapp2:
    platform: linux/amd64
    build:
      context: ../LADevStuff2
    container_name: logicapp2
    ports:
      - "7072:7072"
    environment:
      AzureWebJobsStorage: "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1;TableEndpoint=http://azurite:10002/devstoreaccount1"
      WORKFLOWS_STORAGE_PROVIDER: "AzureStorage"
      WORKFLOWS_STORAGE_CONNECTION_STRING: "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1;TableEndpoint=http://azurite:10002/devstoreaccount1"
      FUNCTIONS_WORKER_RUNTIME: "node"
      AzureWebJobsFeatureFlags: "EnableMultiLanguageWorker"
      AzureWebJobsSecretStorageType: "Files"
      APP_KIND: "workflowapp"
      WEBSITE_SITE_NAME: "logicapp-local2"
    extra_hosts:
      - "localhost:host-gateway"
    depends_on:
      - azurite
      - servicebus-emulator
    networks:
      - shared-network

networks:
  shared-network:
    driver: bridge
Enter fullscreen mode Exit fullscreen mode

Key Configuration Notes:

  • mem_limit: 8g - Critical for Service Bus stability
  • platform: linux/amd64 - Required for Apple Silicon (ARM) Macs
  • extra_hosts: localhost:host-gateway - Enables Logic Apps to reach Service Bus emulator
  • MSSQL Server 2022 - Use this, not SQL Edge (SQL Edge causes crashes)

Step 3: Logic App Configuration

3.1 Connection String Setup

LADevStuff2/local.settings.json

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "servicebusconnection": "Endpoint=sb://localhost:5672;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”‘ Important: Use localhost:5672, not the container name, due to extra_hosts configuration.

3.2 Service Bus Connection

LADevStuff2/connections.json

⚠️ Critical: You cannot create Service Bus connections in the Logic App Designer for queues and topics.

Workaround: Manually edit this file:

{
  "managedApiConnections": {},
  "serviceProviderConnections": {
    "serviceBus": {
      "parameterValues": {
        "connectionString": "@appsetting('servicebusconnection')"
      },
      "parameterSetName": "connectionString",
      "serviceProvider": {
        "id": "/serviceProviders/serviceBus"
      },
      "displayName": "sbConnection"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Then specify queue/topic/subscription names as custom values in your workflow triggers.


Step 4: Workflow Examples

4.1 Message Sender (wf7_sb_send)

LADevStuff2/wf7_sb_send/workflow.json

πŸ’‘ Key Point: userProperties.orderType is used by SQL filters to route messages.

4.2 SB Receivers (wf4,wf5,wf6)

LADevStuff2/wf4/workflow.json

πŸ“ Note: queueName, topicName, and subscriptionName are specified as custom values in the trigger, not selected from a dropdown.

🎯 wf5 : Receives only messages where user.orderType = 'TypeA' (defined in Config.json)

🎯 wf6 : Receives only messages where user.orderType = 'TypeB' (defined in Config.json)


Step 5: Start Everything

cd DockerFiles
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Verify Service Bus is running:

docker logs servicebus-emulator-shared --tail 20
Enter fullscreen mode Exit fullscreen mode

Look for:

info: Emulator Service is Successfully Up!
info: Creating queue: local-orders-queue
info: Creating topic: local-orders-topic
info: Entity Sync complete; Operation Result:True
Enter fullscreen mode Exit fullscreen mode

Check all containers:

docker compose ps
Enter fullscreen mode Exit fullscreen mode

All should show status "Up".


Step 6: Test the Workflows

Send TypeA Order

Making the HTTP Request

Use Postman (or curl) to send a POST request to the wf7_sb_send workflow:

What happens:

  1. HTTP POST triggers wf7_sb_send with payload {"OrderType": "TypeA"}
  2. The workflow sends the message to:
    • Queue: local-orders-queue (no filtering)
    • Topic: local-orders-topic with userProperties.orderType = "TypeA"
  3. The userProperties field is what SQL filters use for message routing

Workflow Execution

RunHistory Viewer shows the send workflow successfully completed:

Expected behavior:

  • βœ… wf4 processes message from queue (all messages go here)
  • βœ… wf5 processes message from topic (TypeA filter matches)
  • ❌ wf6 does NOT process (TypeB filter doesn't match)

Send TypeB Order

Follow the same process as TypeA, but change the payload to:

{ "OrderType": "TypeB" }
Enter fullscreen mode Exit fullscreen mode

Note: You can also extension to send simply payloads, refer below gif

Expected behavior:

  • βœ… wf4 processes message from queue (receives all messages)
  • ❌ wf5 does NOT process (TypeA filter doesn't match)
  • βœ… wf6 processes message from topic (TypeB filter matches)

The SQL filters ensure each workflow only receives messages matching its subscription criteria.


Step 7: Verify Execution

Use the RunHistory Viewer in VS Code to verify workflow executions:

Topic Subscriber (wf5) - TypeA Filter

The screenshot shows the workflow successfully received and processed messages filtered by user.orderType = 'TypeA'.

Queue Receiver (wf4) - All Messages

The screenshot shows the workflow processing all messages from the queue, regardless of message properties.


Key Takeaways

βœ… Memory is critical - 15.6GB Docker, 8GB Service Bus, 2GB MSSQL
βœ… Use MSSQL Server 2022 - Not SQL Edge
βœ… extra_hosts configuration - Required for Docker networking
βœ… SQL filters use user. prefix - For custom properties
βœ… Manually edit connections.json - Designer doesn't support queue/topic setup
βœ… localhost:5672 connection string - Due to extra_hosts configuration
βœ… Rebuild containers - After workflow changes


Summary

You now have a complete local development environment with:

βœ… Service Bus Emulator running in Docker
βœ… Queue for point-to-point messaging
βœ… Topic with SQL-filtered subscriptions for pub/sub
βœ… Multiple Logic Apps in containers
βœ… Proper memory configuration for stability
βœ… Working examples (wf4, wf5, wf6, wf7)

This setup is perfect for:

  • Local development and testing
  • Learning Logic Apps and Service Bus patterns
  • Integration demos
  • Offline development

You can later swap the emulator connection string for Azure Service Bus without changing your workflows!

Happy integrating! πŸš€πŸ³

Top comments (0)