DEV Community

Manohari Jayachandran
Manohari Jayachandran

Posted on

Azure Integration Services Interview Prep Part 1: Service Bus, Storage Queues, Event Hub, and Event Grid

Azure integration services get confused with each other constantly, in interviews and in real architecture decisions - four different services can all technically "move data between two systems," but they solve different problems, at different scales, with different guarantees. This is Part 1 of a series built for panel-level interview prep, covering the services that come up most often, starting with the four that most directly overlap in what they sound like they do: Service Bus, Storage Queues, Event Hub, and Event Grid.

Service 1: Azure Service Bus

Azure Service Bus is an enterprise message broker built for reliable, ordered delivery of discrete business messages between applications, with genuine guarantees - transactions, sessions, dead-letter queues, and topic and subscription fan-out.

Think of a certified mail service. Each message is a specific, individually important letter - tracked, guaranteed to arrive, with a documented trail if delivery fails, and optionally requiring a signature, a transaction, confirming it was genuinely received and processed correctly.

Service Bus fits when the correctness of an individual message actually matters - an order confirmation, a payment event, an integration handoff between two business systems - not just "get this data over there eventually."

Core capabilities that set it apart: queues for one sender and one logical consumer group, topics for one message reaching many independent subscribers, sessions guaranteeing ordered processing for related messages, dead-letter handling so failed messages are quarantined rather than silently lost, and transactions ensuring multiple operations succeed or fail together.

// Sending a message
var client = new ServiceBusClient(connectionString);
var sender = client.CreateSender("order-queue");

var message = new ServiceBusMessage(
    JsonSerializer.Serialize(new { OrderId = "ORD-001", Amount = 49.99 })
);
message.MessageId = Guid.NewGuid().ToString();
message.ApplicationProperties["Priority"] = "High";

await sender.SendMessageAsync(message);

// Receiving and processing
var processor = client.CreateProcessor("order-queue");

processor.ProcessMessageAsync += async args =>
{
    var order = JsonSerializer.Deserialize<Order>(args.Message.Body.ToString());
    await ProcessOrderAsync(order);
    await args.CompleteMessageAsync(args.Message);
    // Not completing (or an exception) = automatic retry,
    // eventually dead-lettered after max retries
};

await processor.StartProcessingAsync();
Enter fullscreen mode Exit fullscreen mode

Service Bus: Problem Scenario and Solving Strategy

The problem: an order-processing system needs every order to be processed exactly once, in the order it was placed per customer, and if processing fails, the order must never be silently lost - someone needs to be able to see and investigate exactly which orders failed and why.

The strategy, step by step:

  • First, recognize this needs real delivery guarantees, not just "a queue" - the ordering-per-customer requirement alone rules out Storage Queue and Event Hub immediately.

  • Second, use Azure Service Bus with sessions enabled, setting SessionId to CustomerId on every message, since Service Bus guarantees all messages with the same SessionId are processed in order by the same consumer.

  • Third, configure a dead-letter queue with a reasonable max delivery count, around 5 attempts, so failed messages move to the dead-letter queue automatically after exhausting retries rather than disappearing.

  • Fourth, build a monitoring dashboard or alert on dead-letter queue message count, since anything landing there needs human investigation.

  • Finally, for true exactly-once semantics, combine this with an idempotency check on the consumer side, checking that an OrderId hasn't already been processed - Service Bus guarantees at-least-once delivery by default, so a rare duplicate delivery is still technically possible, and the consumer itself should be idempotent as a final safety net.

Service 2: Azure Storage Queues

Azure Storage Queues provide a simple, extremely cheap, high-volume queue built on top of Azure Storage - basic FIFO-ish delivery, no transactions, no sessions, no dead-letter queue as a first-class feature, though a manual pattern can approximate one.

Think of a basic ticket dispenser at a deli counter. It hands out numbers in order and gets the job done reliably for simple cases - but there's no certified tracking, no guaranteed same-person-handles-related-tickets behavior, and no built-in "this ticket was never claimed, someone should look into it" process.

Storage Queues fit genuinely simple task queues at high volume, where the cost difference versus Service Bus actually matters, and the missing enterprise features, sessions, transactions, native dead-lettering, aren't needed.

Core characteristics: meaningfully cheaper than Service Bus at scale, a minimal API surface that's easy to reason about, a max message size of 64 KB versus Service Bus's much larger limit, and no native dead-letter queue, sessions, or topics.

// Sending a message
var queueClient = new QueueClient(connectionString, "task-queue");
await queueClient.CreateIfNotExistsAsync();

await queueClient.SendMessageAsync(
    JsonSerializer.Serialize(new { TaskId = 123, Action = "Resize" })
);

// Receiving and processing
QueueMessage[] messages = await queueClient.ReceiveMessagesAsync(maxMessages: 10);

foreach (var message in messages)
{
    var task = JsonSerializer.Deserialize<TaskItem>(message.MessageText);
    await ProcessTaskAsync(task);

    // Must explicitly delete - otherwise the message
    // reappears after its visibility timeout expires
    await queueClient.DeleteMessageAsync(message.MessageId, message.PopReceipt);
}
Enter fullscreen mode Exit fullscreen mode

Storage Queue: Problem Scenario and Solving Strategy

The problem: a system needs to process millions of simple image-resize tasks per day. Each task is independent - order between tasks doesn't matter, tasks don't need to relate to each other, and losing an occasional task isn't business-critical as long as the vast majority succeed. Cost efficiency at this volume matters significantly.

The strategy, step by step:

  • First, recognize the requirements don't need Service Bus's heavier feature set - no ordering, no sessions, no strict zero-loss guarantee, high volume, cost-sensitive.

  • Second, use Azure Storage Queue specifically because of this mismatch, since paying for Service Bus's guarantees here would be genuine overkill.

  • Third, use a Function App with a Queue Trigger to process messages as they arrive, auto-scaling with volume.

  • Fourth, implement a simple manual poison-message pattern - Storage Queue tracks a DequeueCount automatically, so check this count and move a message to a separate failed-tasks queue manually if it exceeds a threshold, approximating the dead-letter behavior Service Bus would give natively.

  • Finally, monitor queue length as the primary health signal, since a queue that keeps growing faster than it's being drained indicates the processing side needs to scale up or investigate a bottleneck.

Service 3: Azure Event Hub

Azure Event Hub is a big-data streaming platform built to ingest and process massive volumes of events per second - millions of small events, not individual important business messages. It's built around the concept of a continuous, ordered log that multiple independent consumers can read from, at their own pace, without removing data from the stream.

Think of a continuously running river of water, versus Service Bus's individually addressed certified letters. You don't pick up one specific event and remove it - you dip a bucket in at whatever point in the river you're currently reading from, and the river keeps flowing regardless of who's watching.

Event Hub fits telemetry ingestion, application logs at scale, IoT sensor data, and clickstream analytics - anywhere the meaningful unit is the aggregate pattern across millions of events, not any single event's individual fate.

Core characteristics: the stream is split into partitions for parallel throughput, consumer groups allow multiple independent readers each tracking their own position in the stream, retention keeps events for a configured window of hours to days rather than removing them on read, and the whole service is built for massive throughput of millions of events per second.

// Sending events
var producerClient = new EventHubProducerClient(connectionString, "telemetry-hub");

using EventDataBatch eventBatch = await producerClient.CreateBatchAsync();
eventBatch.TryAdd(new EventData(
    JsonSerializer.Serialize(new { DeviceId = "sensor-42", Temp = 21.5 })
));
await producerClient.SendAsync(eventBatch);

// Reading events - note the CONSUMER GROUP concept,
// each independent reader tracks its own position
var consumerClient = new EventHubConsumerClient(
    EventHubConsumerClient.DefaultConsumerGroupName,
    connectionString,
    "telemetry-hub"
);

await foreach (PartitionEvent partitionEvent in consumerClient.ReadEventsAsync())
{
    var data = Encoding.UTF8.GetString(partitionEvent.Data.EventBody.ToArray());
    Console.WriteLine(data);
}
Enter fullscreen mode Exit fullscreen mode

Event Hub: Problem Scenario and Solving Strategy

The problem: a fleet of 50,000 IoT sensors each sends a temperature reading every 5 seconds - roughly 10,000 events per second sustained. This data needs to be ingested reliably at that volume, and multiple independent systems need to read the same stream: one for real-time alerting, one for long-term storage and analytics, without either consumer affecting the other or removing data the other still needs to read.

The strategy, step by step:

  • First, recognize this is fundamentally a streaming and volume problem, not a discrete-message problem - 10,000 events per second immediately rules out Service Bus and Storage Queue, since neither is built for this throughput.

  • Second, use Azure Event Hub specifically for its partition-based architecture, built to sustain this event rate.

  • Third, configure multiple partitions so ingestion can happen in parallel, with partition count chosen based on expected throughput and downstream consumer count.

  • Fourth, create two separate consumer groups - one for the real-time alerting system, one for the analytics and storage pipeline - since each consumer group tracks its own independent read position, neither interferes with the other's pace or progress.

  • Fifth, use Event Hubs Capture, a built-in feature, to automatically archive raw events to Blob Storage for long-term retention, decoupling the archival need from requiring a custom consumer to handle it manually.

  • Finally, size the retention window based on how far behind a consumer might realistically fall before catching up, since this determines how much buffer exists before older events age out of the stream.

Service 4: Azure Event Grid

Azure Event Grid is a reactive event routing service - "when X happens, notify these subscribers." It doesn't hold messages waiting to be pulled, and it isn't built for high-volume streaming - it's a lightweight, push-based notification layer that reacts to discrete events and routes them to interested subscribers.

Think of a building's fire alarm system, versus Service Bus's certified mail or Event Hub's continuous river. Nothing sits in a queue waiting - the moment smoke is detected, every subscribed system, sprinklers, the fire department, building announcements, is notified simultaneously and immediately. The alarm doesn't store history of past fires; it reacts to the event as it happens.

Event Grid fits reacting to a specific occurrence - a blob was uploaded, a resource was created or deleted, a custom application event happened - and triggering downstream systems, often Function Apps or Logic Apps, in near real time.

Core characteristics: push-based delivery means subscribers are notified immediately rather than polled, many Azure services publish built-in resource events to Event Grid automatically, custom topics let your own application publish its own custom events too, and it is not designed for high-volume streaming or as a durable queue.

// Publishing a custom event
var client = new EventGridPublisherClient(
    new Uri(topicEndpoint),
    new AzureKeyCredential(topicKey)
);

var eventGridEvent = new EventGridEvent(
    subject: "Posts/NewPostPublished",
    eventType: "TechStackBlog.PostPublished",
    dataVersion: "1.0",
    data: new { PostId = 34, Slug = "azure-integration-interview-prep-part1" }
);

await client.SendEventAsync(eventGridEvent);

// A Function App reacting to a BUILT-IN Azure event -
// this example reacts automatically when a blob is
// uploaded to storage, no polling required
[Function("OnBlobUploaded")]
public async Task Run(
    [EventGridTrigger] EventGridEvent eventGridEvent)
{
    if (eventGridEvent.EventType == "Microsoft.Storage.BlobCreated")
    {
        var blobUrl = eventGridEvent.Data.ToString();
        await ProcessNewBlobAsync(blobUrl);
    }
}
Enter fullscreen mode Exit fullscreen mode

Event Grid: Problem Scenario and Solving Strategy

The problem: whenever a new image is uploaded to Blob Storage, three completely independent things need to happen immediately - generate a thumbnail, run content moderation, and update a search index. These three actions are unrelated to each other, each can fail or succeed independently, and there's no need to hold onto historical upload events, only new uploads matter, reacted to as they happen.

The strategy, step by step:

  • First, recognize this is a reactive routing problem, not a volume or ordering problem - a blob upload is a discrete event that needs to fan out to multiple independent reactions, immediately, with no need for historical replay or streaming.

  • Second, use Azure Event Grid, leveraging its built-in integration with Blob Storage, since no custom code is needed to detect that a blob was uploaded - Azure Storage already publishes this event to Event Grid automatically.

  • Third, create three separate Event Grid subscriptions against the same Blob Storage source event: one triggering a Generate Thumbnail Function App, one triggering a Content Moderation Function App, and one triggering an Update Search Index Function App.

  • Fourth, note that each subscription operates completely independently - if content moderation fails, thumbnail generation is entirely unaffected, since Event Grid delivers to each subscriber separately.

  • Fifth, configure Event Grid's built-in retry policy, exponential backoff with a configurable max retry count, on each subscription individually, tuned to how critical and how flaky each specific downstream action actually is.

  • Finally, for any subscription needing to survive multiple retry failures, configure a dead-letter destination, typically a Storage Blob container, so failed events aren't silently lost - this is Event Grid's equivalent to Service Bus's dead-letter queue, configured per-subscription rather than being automatic.

Choosing Between All Four: The Actual Decision Framework

Ask these questions, in this order. Is this a reaction to a discrete event happening, needing to fan out to multiple independent subscribers immediately? That's Event Grid. Is this a massive volume of small events, thousands or more per second, where the aggregate stream matters more than any single event's individual fate? That's Event Hub. Does this need real delivery guarantees - ordering, transactions, sessions, native dead-lettering - for individually important business messages? That's Service Bus. Is this a simple, high-volume task queue where cost efficiency matters and Service Bus's extra features genuinely aren't needed? That's Storage Queue.

Key Lessons

All four services move data between systems, but they solve genuinely different problems - the real interview skill is matching volume, ordering needs, and delivery guarantees to the correct service, not memorizing a feature comparison table.

Service Bus is the right choice specifically when individual message correctness, ordering, or transactional guarantees matter - Storage Queue is the lighter, cheaper alternative when they don't.

Event Hub and Event Grid are both "event" services but solve opposite-shaped problems - Event Hub handles massive continuous streams, Event Grid handles discrete reactive notifications fanning out to multiple subscribers.

Every problem scenario in this post started with identifying the actual constraint, ordering, volume, fan-out, cost, before picking a service - that ordering of reasoning is what a panel interview is actually listening for.

Native dead-lettering, sessions, and transactions are real, meaningful differentiators, not just checkbox features - they solve specific correctness problems the simpler services genuinely cannot.

What's Next

Future parts of this series will cover additional Azure integration services - Logic Apps and Function Apps as orchestration layers, API Management as the gateway layer, and deeper production patterns for combining these services together in real architectures.

Summary

Service Bus, Storage Queues, Event Hub, and Event Grid all sound similar on the surface, since all four move data between systems, but they solve genuinely different problems at genuinely different scales. Service Bus guarantees correctness for individually important messages. Storage Queue trades those guarantees for simplicity and cost at high volume. Event Hub ingests and streams massive volumes of small events. Event Grid reactively routes discrete events to multiple independent subscribers. Knowing which constraint actually matters in a given scenario, and reasoning through that out loud, is what separates a memorized answer from a genuinely confident one in a panel interview.


More from TechStack Blog: Azure: https://www.techstackblog.com/category.html?cat=azure
CS Fundamentals: https://www.techstackblog.com/category.html?cat=cs-fundamentals

Top comments (0)