Commands, events or streams?
| Message kind | Meaning | Typical service |
|---|---|---|
| Command / work item | "Do this" (process order 1234). One consumer must handle it, reliably | Service Bus queue (or Storage Queue for simple cases) |
| Discrete event | "This happened" (blob created, VM deallocated). Zero or many interested parties react | Event Grid |
| Event stream / telemetry | Many events per second, read in order per partition, replayable | Event Hubs |
| Business event to many subscribers with guarantees | "Order placed" to billing, shipping, email | Service Bus topics |
Comparison
| Service Bus | Event Grid | Event Hubs | Storage Queues | |
|---|---|---|---|---|
| Model | Queue / pub-sub broker | Push (and pull) event routing | Partitioned log | Simple queue |
| Ordering | FIFO with sessions | Not guaranteed | Per partition | Not guaranteed |
| Delivery | At-least-once, peek-lock, dead-letter | At-least-once with retries, dead-letter to storage | Consumer tracks position (checkpoints) | At-least-once, visibility timeout |
| Retention | Until consumed (TTL) | Short retry window | Time-based retention, replay | Until consumed (TTL) |
| Transactions, duplicate detection, scheduling | Yes | No | No | No |
| Throughput | High | High fan-out | Very high (streams) | High, simple |
| Typical consumers | Workers, microservices | Functions, Logic Apps, webhooks | Stream processing, Databricks, ADX, Fabric | Simple workers |
Check message size limits and tier features (Basic/Standard/Premium for Service Bus; tiers for Event Hubs) for your design.
Decision questions
- Does the sender care that exactly this work gets done? → Service Bus.
- Do you need ordering per customer/order? → Service Bus sessions or Event Hubs partitions keyed by that id.
- Do consumers need to replay history? → Event Hubs.
- Is it reacting to Azure resource changes or fanning out notifications? → Event Grid.
- Is it a simple background job queue with low feature needs? → Storage Queues.
Common combined patterns
Blob uploaded ─► Event Grid ─► Service Bus queue ─► worker (reliable processing, retries, DLQ)
IoT / app telemetry ─► Event Hubs ─► stream processing ─► Data Explorer / lakehouse
Order service ─► Service Bus topic ─► subscriptions: billing | shipping | notifications
Event Grid straight to a Function is fine for light work; putting a Service Bus queue in between gives you buffering, dead-lettering and control over concurrency.
Failure handling you must design
| Service | Design |
|---|---|
| Service Bus | Max delivery count, dead-letter queue monitoring and replay, idempotent handlers |
| Event Grid | Retry policy, dead-letter destination, event filtering to avoid floods |
| Event Hubs | Checkpointing strategy, consumer lag alerts, poison event handling in code |
| Storage Queues | Poison queue handling, visibility timeout vs processing time |
Idempotency is required everywhere. At-least-once delivery means duplicates will happen.
Operational signals
- Service Bus: active and dead-lettered message count, oldest message age.
- Event Hubs: incoming vs outgoing messages, consumer lag, throttled requests.
- Event Grid: delivery failures, dead-lettered events, matched vs delivered.
Warning
Using Event Hubs as a work queue (one message = one job that must be done once) or Event Grid as a guaranteed business workflow causes lost or repeated work later. Match the service to the message kind.
Checklist
- Message kind identified (command, event, stream)
- Ordering, replay and guarantee needs answered
- Tier and limits checked
- Dead-letter and retry handling designed
- Idempotent consumers
- Lag/backlog alerts in place