Azure Architecture Guide

CH15-04: Consistency, Latency, and Event-Driven Trade-Offs

Goal

The previous section sketched a target architecture. This section explains one of its most important choices: what should happen in the customer request path and what should continue asynchronously.

The durable idea is:

Event-driven design helps commerce platforms absorb complexity, but it does not remove correctness responsibilities.

The Short Version

Asynchronous processing is valuable in commerce because many important tasks do not need to finish before the customer receives a response. Fulfillment handoff, notifications, analytics, search projections, support views, and some inventory workflows can continue after order creation.

But asynchronous does not mean vague. The platform still needs clear order state, idempotency, retry rules, duplicate handling, dead-letter queues, observability, ownership, and customer-visible status.

The design question is not "Should we use events?" The better question is:

Which decision must be made now, which work must complete later, and how will the system prove what happened?

The Checkout Split

Checkout is where the synchronous and asynchronous worlds meet.

Checkout request
    -> validate identity, cart, price, availability, fraud, and payment boundary
    -> create durable order state
    -> return clear customer outcome
             |
             +-> durable fulfillment work
             +-> notification work
             +-> analytics and search projections
             +-> support and tracking projections

The synchronous path should do enough to make a trustworthy customer decision. The asynchronous path should carry the rest of the work durably.

For example, a customer should not wait for every warehouse system, carrier system, email provider, analytics pipeline, and recommendation update before seeing an order confirmation. At the same time, the platform should not return success if it has not created durable order state.

What Should Stay Synchronous

Keep work synchronous when the customer response depends on it.

ResponsibilityWhy It Usually Stays in the Request Path
Authenticate customer or callerThe platform must know who is acting.
Validate cart contentsThe order should not be created from invalid or stale cart state.
Recalculate price, promotion, and tax inputs where neededThe customer needs a clear commercial decision.
Check fraud and payment authorization boundaryThe platform should not create a normal confirmed order if payment or fraud state is unresolved.
Create order record or clear pending stateThe platform needs durable evidence before it tells the customer what happened.
Return confirmation, rejection, or pending statusThe customer needs an understandable outcome.

There are exceptions. Some businesses support delayed payment capture, preorder, backorder, manual fraud review, or pending confirmation. Those are valid patterns, but the status must be explicit. Ambiguous success is dangerous.

What Can Continue Asynchronously

Move work asynchronous when it is important but does not need to block the immediate customer response.

ResponsibilityWhy It Can Often Be AsynchronousRequired Control
Fulfillment handoffWarehouse and delivery workflows may take time.Durable message, status tracking, retry, owner.
Customer notificationEmail or push providers can be slow or unavailable.Retry, fallback, communication history.
Inventory workflow updatesReservation, allocation, and replenishment may involve other systems.Idempotent commands, workflow state, exception path.
AnalyticsReporting does not need to block checkout.Event quality, replay, late-arrival handling.
Search and support projectionsRead models can update after order creation.Projection lag monitoring and repair path.

This is where Service Bus, Event Grid, Azure Functions, Container Apps workers, Logic Apps, or durable workflow services may appear. The service choice depends on the communication contract.

Commands, Events, and Streams

Commerce designs often confuse communication styles.

StylePlain-Language MeaningCommerce ExampleAzure Fit
CommandPlease do this work.Fulfill order 123.Service Bus queue or topic, workflow service.
EventThis fact happened.Order 123 was created.Event Grid or Service Bus topic, depending on durability and subscriber needs.
StreamMany records for analysis or processing.Clickstream, product views, telemetry.Event Hubs or analytics ingestion path.
WorkflowCoordinate multiple steps over time.Reserve inventory, create warehouse task, handle carrier exception.Logic Apps, Durable Functions, or application workflow engine.

The terms matter because failure behavior differs. A command that must complete needs a durable owner. An event may have many subscribers, and each subscriber owns its reaction. A stream is not a task queue. A workflow needs state and decisions over time.

Reliability Controls

Asynchronous commerce work needs reliability controls from the start.

ControlWhat It Protects
IdempotencyThe same request or message can be handled more than once without creating duplicate side effects.
Duplicate detectionRepeated messages or repeated sends do not create duplicate work.
Retry with backoffTemporary failures are retried without overwhelming dependencies.
Dead-letter handlingMessages that repeatedly fail move to an investigation path.
Correlation IDsOne customer action can be traced across APIs, queues, workers, and logs.
Status modelCustomers and support teams can see whether work is created, pending, failed, delayed, or complete.
Replay rulesOperators know when it is safe to reprocess messages or events.
OwnershipSomeone is accountable for stuck queues, failed messages, and customer impact.

Without these controls, asynchronous design merely moves confusion out of the request path.

Example: Notification Failure After Order Creation

A customer completes checkout. Payment authorization succeeds, the order record is created, and a message is placed on a queue for downstream processing. The email provider is unavailable when the notification worker tries to send confirmation.

The order should not disappear. The customer should still be able to see the order in order history. The notification worker should retry according to policy. If repeated attempts fail, the message should move to a dead-letter or exception path with enough context for investigation. Operators should see the failure rate and message age. Support agents should be able to tell the customer that the order exists even if the email is delayed.

That is the difference between reliable asynchronous processing and hopeful background work.

Common Mistakes

  • Using events as a way to avoid defining order state. Events describe changes; they do not replace a clear state model.

  • Ignoring idempotency and duplicate prevention. Customers notice duplicate orders, duplicate charges, and repeated notifications.

  • Letting downstream failures corrupt the customer-facing order experience. Failure should be visible and recoverable, not silently mixed into checkout success.

  • Treating every integration as an event. Commands, events, streams, and workflows solve different problems.

  • Creating dead-letter queues without alerts, dashboards, runbooks, or owners.

If Someone Asks You

I would keep checkout validation, payment boundary coordination, and durable order creation in the immediate request path. Then I would move fulfillment handoff, notifications, analytics, projections, and some inventory workflows to asynchronous processing. For work that must complete, I would use durable messaging such as Service Bus and design idempotency, retries, dead-letter handling, correlation IDs, replay rules, status visibility, and ownership.

What You Should Remember

Asynchronous processing protects the request path only when state, retries, and observability are designed.

Questions to Check Your Understanding

  1. Which checkout responsibilities should stay synchronous?

  2. Why does idempotency matter in order processing?

  3. What should happen when a downstream notification fails?