Azure Architecture Guide

CH11-05: Event Contracts, Observability, and Operations

Goal

The previous sections showed how events are routed, handled, and sometimes turned into durable work. This section focuses on the decisions that keep that distributed flow understandable after the first demo works.

Event-driven systems can fail quietly. One event may pass through a router, a handler, a queue, a worker, a database, and a notification system. If teams cannot trace that flow, the architecture becomes difficult to operate.

The durable idea is:

Event-driven systems need contract discipline and observability because the workflow is distributed.

The Short Version

An event-driven architecture is operable when teams can answer four questions:

What happened?
Who published it?
Who was supposed to react?
What happened when they tried?

Those answers depend on contracts, correlation, logs, metrics, traces, alerts, dashboards, replay rules, and ownership.

Event Contracts

An event contract defines what the event means and how consumers should understand it.

At minimum, teams should define:

Contract ElementWhy It Matters
Event nameConsumers need to know what fact occurred.
SchemaConsumers need predictable fields and types.
VersionProducers need a way to evolve the event safely.
Subject or business keyTeams need to connect the event to an order, file, customer, resource, or process.
Correlation IDTroubleshooting needs a thread through asynchronous components.
Producer ownerSomeone must explain and maintain the event.
Compatibility rulesConsumers need to know which changes are safe.
Payload policyTeams need rules for sensitive data, size, and references to stored data.

The event schema should be treated like a public API between teams. If a producer changes field names, removes fields, changes meanings, or publishes inconsistent event types, subscribers can break even though no direct API call changed.

Versioning and Compatibility

Event versioning is not only a naming exercise. It is an agreement about change.

Safe changes often include adding optional fields or clarifying documentation without changing existing meanings. Risky changes include removing fields, changing data types, changing event meaning, or reusing the same event name for a different business fact.

A practical approach is:

  • Keep event names stable and meaningful.

  • Add new optional fields before removing old ones.

  • Let subscribers tolerate unknown fields.

  • Use explicit versions when a breaking schema or meaning change is unavoidable.

  • Document who owns the event and how subscribers are notified about changes.

CloudEvents or similar event-format conventions can help teams use consistent metadata, but the architecture still needs business-specific ownership and compatibility rules.

Observability Signals

Event-driven flow needs observability because there may be no single caller waiting for a response.

Useful signals include:

SignalWhat It Helps You See
Correlation IDOne business action across producer, router, handlers, queues, and workers.
Structured logsWhat each component received, decided, attempted, and completed.
MetricsEvent counts, handler failures, latency, retries, queue depth, and dead-letter counts.
Distributed tracingThe path and timing of work across services where supported.
DashboardsOperational state for teams and incident response.
AlertsConditions that need action before customers report the problem.

The goal is not to log everything forever. The goal is to capture enough information to answer where an event went, which component failed, whether work is stuck, and what the business impact is.

Ownership Map

In a small system, one team may own the whole flow. In a larger system, ownership is split. Make that split explicit.

OwnerTypical Responsibility
Producer teamEvent meaning, schema, versioning, publishing reliability, and source-side logs.
Platform or integration teamEvent Grid topics, subscriptions, access control, routing patterns, and shared standards.
Subscriber teamHandler code, validation, idempotency, dependency calls, and local failures.
Queue or worker ownerBacklog, message age, retry policy, dead-letter review, and replay safety.
Operations or SRE teamDashboards, alerts, incident response, runbooks, and cross-service visibility.
Security teamIdentity, access, sensitive payload rules, audit requirements, and policy alignment.

If nobody owns a dead-letter queue, then nobody owns the business work that failed. If nobody owns the schema, then every subscriber becomes fragile.

Ordering, Idempotency, and Replay

Event-driven systems often deliver at least once rather than exactly once. That means handlers should expect duplicate attempts and process safely.

Idempotency means the same event or message can be processed more than once without creating the wrong business result. For example, processing the same ThumbnailGenerationRequested message twice should not create two conflicting records or send duplicate customer notifications.

Ordering should also be scoped carefully. Many teams say "events must be ordered" when they really mean ordering matters for one order, one customer, one document, or one workflow instance. Narrow ordering requirements are easier to design and operate than global ordering assumptions.

Replay is powerful but risky. Reprocessing old events can repair a failure or rebuild a projection, but it can also repeat side effects, call external systems again, or overwrite newer data. Replay should have clear rules.

Cost and Operational Trade-Offs

Event-driven systems can spread cost across many places:

  • Event routing volume.

  • Handler compute executions or container scale.

  • Service Bus operations and stored messages.

  • Logs, traces, and metric ingestion.

  • Retries that repeat downstream calls.

  • Dead-letter storage and investigation.

  • Extra databases or state stores used for idempotency and progress tracking.

This does not mean event-driven architecture is too expensive. It means cost should be part of the design. A noisy event that triggers five handlers and heavy logging can become expensive quickly. A poorly tuned retry policy can increase downstream load during an incident.

Example: Schema Change Breaks a Subscriber

A document platform publishes ContractDocumentUploaded events. The search team depends on a documentType field. Later, the producer renames the field to contentType without a compatibility period.

The upload still works. Event Grid still routes the event. The handler still starts. But the search subscriber cannot classify the document, indexing fails, and messages begin to accumulate in a dead-letter path.

This is not only a coding mistake. It is a contract and ownership failure. A better design would define schema versioning, compatibility rules, test events, subscriber notification, correlation IDs, and alerts for failed indexing.

Common Mistakes

  • Publishing events without schema ownership or versioning rules.

  • Troubleshooting event flows without correlation IDs.

  • Creating queues and dead-letter paths without dashboards, alerts, and runbooks.

  • Assuming every subscriber understands the same ordering or retry expectations.

  • Treating log volume, retries, and downstream calls as free.

  • Forgetting to document event meaning for future teams.

If Someone Asks You

What makes an event-driven architecture operable?

A good answer is:

An event-driven architecture is operable when event contracts are owned and versioned, each event can be traced across routing and processing, failures have visible paths, retries and idempotency are designed, and teams know who owns schemas, handlers, queues, dead-letter messages, alerts, and cost.

What You Should Remember

Events need named contracts, traceable flow, owned failures, and cost awareness.

Questions to Check Your Understanding

  1. Why do event schemas need owners?

  2. What signals help trace an event flow?

  3. How can retries affect cost and downstream systems?