This sample shows a reversible architecture where you can switch messaging backends without changing application code. Dapr pub/sub abstracts the broker so you can run locally with RabbitMQ or in a cloud-like mode with Azure Service Bus. The startup scripts automatically stop any existing environment and build containers when needed; after that, switching backends reuses the same images.
- Java services (Spring Boot)
reversible-api(API): publishes customer events through Daprreversible-observer(Observer): subscribes to the same events via Dapr
- React
customer-webappUI to interact with the API - PostgreSQL for persistence (pre-seeded data)
- Dapr sidecars + components for pub/sub
- Aspire Dashboard for local telemetry
The API emits customer events to the Dapr pub/sub component. The Observer subscribes to the topic and logs what it receives. You can confirm this behavior by tailing the observer container logs.
- First run of either start script will build the Docker images if they’re missing (no separate build step required).
- When you switch between RabbitMQ and Azure Service Bus, you don’t need to rebuild the images. The Dapr components change, not the Java or React code.
- You don’t need to run a separate stop script—the start scripts stop any existing environment automatically.
When running the Azure environment, you need an existing Azure Service Bus with a topic for the sample’s events:
- Create (or reuse) a Service Bus namespace
- Create a Topic named
customer-events - Get the connection string (with Manage or Send/Listen as appropriate)
- Put the connection string in
docker/dapr/secrets.jsonunder the keyservicebus-connection-string- See
docker/dapr/secrets.json.samplefor the expected JSON structure
- See
Dapr’s Azure Service Bus component (docker/dapr/components-azure/pubsub.yaml) reads that secret via the local file secret store (docker/dapr/components-azure/secrets.yaml).
Prerequisites:
- Windows with PowerShell (pwsh)
- Docker Desktop running
From the repo root, pick one mode:
- (Optional) Create secrets file if you don’t have one yet:
Copy-Item docker/dapr/secrets.json.sample docker/dapr/secrets.json -ErrorAction SilentlyContinue
# For RabbitMQ mode, you can keep only the Service Bus key empty; RabbitMQ connection is embedded in the component config.- Start:
pwsh ./start-rabbitmq.ps1Services and endpoints:
- Webapp: http://localhost:8083
- API: http://localhost:8081
- Observer: http://localhost:8090
- PostgreSQL: localhost:5432
- RabbitMQ Management: http://localhost:15672 (admin/admin123)
- Aspire Dashboard: http://localhost:18888
- Create secrets file and set your connection string:
Copy-Item docker/dapr/secrets.json.sample docker/dapr/secrets.json
# Edit docker/dapr/secrets.json and set:
# {
# "servicebus-connection-string": "Endpoint=sb://<yournamespace>.servicebus.windows.net/;SharedAccessKeyName=<name>;SharedAccessKey=<key>"
# }- Start:
pwsh ./start-azure.ps1Services and endpoints:
- Webapp: http://localhost:8083
- API: http://localhost:8081
- Observer: http://localhost:8090
- PostgreSQL: localhost:5432
- Aspire Dashboard: http://localhost:18888
The observer subscribes to the customer-events topic (via Dapr Subscription). To watch it process messages, stream logs from the observer container:
# Azure Service Bus mode
docker-compose -f docker/docker-compose-azure.yml logs -f observer
# RabbitMQ mode
docker-compose -f docker/docker-compose-rabbitmq.yml logs -f observerYou should see log entries whenever you interact with the app (e.g., creating/updating customers through the API/webapp).
To switch backends, just run the other start script. It will stop the currently running environment automatically and start the selected one:
# From Azure -> RabbitMQ
pwsh ./start-rabbitmq.ps1
# From RabbitMQ -> Azure (ensure your Service Bus connection string is set)
pwsh ./start-azure.ps1No application code changes are needed; Dapr components handle the difference.
- If a start script fails early, ensure Docker Desktop is running and that required files exist:
docker/dapr/secrets.jsonwithservicebus-connection-stringfor Azure mode
- Use the Aspire Dashboard at http://localhost:18888 to inspect traces and logs.
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit Contributor License Agreements.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.