Running Azure messaging locally with the native SDK: AMQP vs HTTPS
When you build against Azure messaging, your code uses an official SDK and your tests should too — unmodified, config-only. The catch is the wire protocol. Azure Service Bus speaks AMQP 1.0, and AMQP is the one transport a local simulator can't cheaply fake. This is how we kept the native Azure SDK working as-is for local queue development by building around HTTP instead — and exactly what that does and doesn't buy you.
1. The wall — AMQP
The native azure-messaging-servicebus SDK speaks AMQP 1.0: long-lived stateful
sessions and links, credit-based flow control, CBS (claims-based-security) auth over a dedicated
link, and a separate management link for entity operations. That's not an HTTP request/response you can serve
with a route handler — it's a stateful binary protocol with its own connection lifecycle.
The obvious escape hatch — Microsoft's Service Bus emulator — is a dead end for an embeddable, cross-platform appliance, for three independent reasons:
- Java entity management is .NET-only. Runtime create/delete of queues/topics via the
Administration client runs over a custom, non-TLS management port that the non-.NET SDKs won't drive — fatal
for a
create → send → receive → deletetest from Java. - amd64-only SQL sidecar. The emulator requires MS SQL Server 2022 (amd64). The ARM-capable Azure SQL Edge was retired 2025-09-30, so there's no clean ARM path.
- Footprint + license. ~1.6 GB SQL image, ~2 GB RAM, under a dev/test-only, non-redistributable EULA — too heavy and too restricted to ship inside a runtime.
2. The tech choice — build around HTTP
Azure has a messaging service that speaks plain HTTP/REST and ships with a real, embeddable
emulator: Storage Queues, served by Azurite (the same container that already
backs Azure Blob in the appliance). So Azure messaging conformance is delivered through the native
azure-storage-queue SDK — full runtime create → send → receive → delete against
Azurite, no AMQP, no SQL sidecar.
// Native azure-storage-queue — unchanged from production except the connection string.
QueueClient queue = new QueueClientBuilder()
.connectionString(System.getenv("AZURE_QUEUE_CONNECTION_STRING")) // Azurite/local
.queueName("orders")
.buildClient();
queue.create();
queue.sendMessage("order-42");
QueueMessageItem msg = queue.receiveMessage();
process(msg.getBody().toString());
queue.deleteMessage(msg.getMessageId(), msg.getPopReceipt()); // ack
queue.delete();
The only line that differs from production is the connection string — and even that is a standard Azure connection string, just pointing at the local queue endpoint. The Azurite backing is invisible to your code and swappable for real Azure Storage.
Under the hood (you don't need this to use it): because theazure-storage-queueSDK rebuilds request URLs from the host (dropping any path prefix), the appliance gives each storage account its own hostname —{account}.queue.localtest.me(resolves to 127.0.0.1, no hosts-file edits) — and a tiny middleware maps that back to the queue handler. Same trick real Azure uses: one hostname per account.
3. The trade-off, stated plainly
Storage Queue is a different service from Service Bus. We label the substitution; we never imply parity.
| You keep | You give up (for now) |
|---|---|
| A real native Azure queue SDK, unmodified | Service Bus topics / subscriptions (pub-sub fan-out) |
Real create → send → receive → delete round-trips | Sessions (ordered, stateful message groups) |
| ARM-native, no SQL sidecar, ARM + amd64 | Transactions and AMQP-only delivery semantics |
| Persistent state, offline | Dead-letter / auto-forward niceties |
If your app genuinely depends on Service Bus topics or sessions, this stub won't model them — and we say so, out loud, rather than returning a green that lies.
4. SDK conformance
The snippet above is the whole point: it's the same client classes, the same calls you ship
to production. There is no Vyomi SDK, no shim, no wrapper. You configure one endpoint (via the connection string)
and the unmodified azure-storage-queue SDK does real work. Swap the connection string for a
production Azure Storage account and the identical code runs against the real cloud.
5. What is guaranteed (Azure messaging)
- Guaranteed: the official
azure-storage-queueSDK, unmodified and config-only; a real create → send → receive → delete round-trip with visibility-timeout semantics; portable code; backing tech (Azurite) invisible and swappable. - Not guaranteed (said out loud): AMQP-only Service Bus features — topics, subscriptions, sessions, transactions; cloud-scale throughput / quotas / billing. The substituted service is labeled — Storage Queue is not Service Bus.
Part of the Vyomi Knowledge Center series on native-SDK conformance. Companion:
“gRPC vs HTTPS” — GCP KMS / Secret Manager.
Verified on a live appliance (2026-06-22): native azure-storage-queue
create→send→receive→delete, green.