Skip to main content

Event Hub Consumer Contracts and Schema Compatibility

Scope

This reference defines the schema surface between Event Hub (the producer) and downstream event bus consumers. It covers the EventHubEvent Protobuf message structure, EventHubType enum values, event bus message format, validation invariants that consumers can rely on, schema evolution rules, and delivery guarantees. Event Hub serializes messages in Protobuf format and manages schemas through Schema Registry.

Definitions

TermDescription
EventHubEventThe top-level Protobuf envelope for all events published to the event bus. Contains metadata fields and a type-specific sub-event payload.
EventHubTypeAn enum that categorizes each event. Each valid value maps to a dedicated event bus topic.
oneof eventA Protobuf oneof field inside EventHubEvent that carries exactly one sub-event payload per message.
Sub-eventA type-specific Protobuf message nested inside the oneof event field. Each EventHubType has its own sub-event structure.
Proto artifactThe versioned artifact containing all Protobuf definitions for Event Hub events. Consumers must include this as a dependency.

Allowed Values / Behavior

EventHubEvent Message Structure

The EventHubEvent message is the top-level Protobuf envelope for all events:

EventHubEvent
├── eventId : string (UUID, required)
├── eventType : EventHubType (required, not UNKNOWN/UNRECOGNIZED)
├── sourceService : string (required)
├── createdAt : google.protobuf.Timestamp
└── oneof event : (exactly one sub-event, required)
├── case A : SubEventTypeA
├── case B : SubEventTypeB
└── case N : SubEventTypeN

Each sub-event type has its own nested structure with type-specific action cases, event types, and payload fields. The exact fields depend on the proto definitions in the Event Hub proto artifact.

EventHubType Enum

Every EventHubEvent carries an eventType field from the EventHubType enum. Each valid value maps to a dedicated event bus topic:

EventHubType ValueValidEvent Bus Topic
A valid event type (e.g., employee lifecycle, external data changes, etc.)YesDedicated topic per event type
EVENTHUB_TYPE_UNKNOWNNo — rejected at validation
UNRECOGNIZEDNo — rejected at validation
note

The specific EventHubType values and their corresponding event bus topics are defined in the Event Hub proto artifact. Refer to the proto definitions for the full list of supported event types in your deployment.

Event Bus Message Format

AspectValue
KeyEventHubEvent.eventId (String)
ValueEventHubEvent Protobuf message
SerializationProtobuf format with Schema Registry integration
Schema RegistrySchema Registry (auto-registers schema per topic)
Delivery guaranteeAt-least-once (outbox pattern with full replica acknowledgment)

Validation Rules (Consumer Invariants)

Event Hub enforces the following validation rules before an event reaches the outbox (and subsequently the event bus). Consumers can rely on these invariants:

RuleDescription
Event presentThe event message must not be empty
Event ID presenteventId must be non-empty
Event type valideventType must be a recognized, valid value
Source service presentsourceService must be non-empty
Sub-event present and validThe oneof event field must contain a valid sub-event that matches the declared eventType
Sub-event fields validEvent Hub validates required fields within the sub-event payload

Event Hub rejects invalid events with a gRPC INVALID_ARGUMENT error — they never reach the outbox or the event bus.

tip

Because Event Hub validates events before writing to the outbox, consumers can assume that any message received from an event bus topic has passed all validation rules above. There is no need to re-validate these invariants on the consumer side.

Schema Evolution

Teams manage proto definitions through versioned artifacts. Schema changes follow these principles:

  • Backward-compatible changes (adding optional fields, adding new enum values) do not require consumer updates
  • Breaking changes (removing fields, changing field types, renaming fields) require coordinated updates between Event Hub and all consumers
  • Schema Registry enforces compatibility rules per topic — configure the compatibility level to match your evolution strategy

Delivery Guarantees

Event Hub provides at-least-once delivery guarantees through the outbox pattern. In rare edge cases (batch update failure after successful event bus send), Event Hub may deliver the same event more than once. Consumers must implement idempotent processing — use eventId (the message key) as the deduplication key.

Event Hub does not guarantee strict ordering across events. However, since eventId serves as the message key, the event bus guarantees that events with the same eventId land in the same partition — providing per-event ordering within a topic.

Proto Artifact Dependency

Consumers must include the Event Hub proto artifact as a dependency to deserialize messages. The artifact contains the Protobuf definitions for EventHubEvent and all sub-event types.

The artifact version must be compatible with the version used by Event Hub. Mismatched versions may cause deserialization failures. Refer to the internal artifact registry for the latest coordinates and version information.

warning

Teams manage proto artifacts from a separate artifact registry. Schema changes require publishing new versions and updating dependency versions on both Event Hub and consumer sides.

Audit Trail

Event Hub sends an audit log to the Audit & Observability component for every received event. The audit entry records the source service, event type, and full event details. When teams enable additional audit logging, Event Hub generates extra audit entries after successful database inserts and event bus sends.

Used By

Minimal Example

Consumer deserialization example
// Event bus consumer configuration — use Protobuf Deserializer
props.put("value.deserializer", "<PROTOBUF_DESERIALIZER>");
props.put("schema.registry.url", "<SCHEMA_REGISTRY_URL>");
props.put("specific.protobuf.value.type",
"<EVENTHUB_EVENT_CLASS_FROM_PROTO_ARTIFACT>");

// Processing
ConsumerRecord<String, EventHubEvent> record = ...;
EventHubEvent event = record.value();

String eventId = event.getEventId(); // UUID string (message key)
EventHubType type = event.getEventType(); // Event category
String source = event.getSourceService(); // Upstream service name

// Access the sub-event via the oneof case
switch (event.getEventCase()) {
case <SUB_EVENT_CASE>:
var subEvent = event.get<SubEvent>();
// Process type-specific payload
break;
default:
// Handle unknown event case
break;
}

Invalid Example

Missing eventId — rejected
EventHubEvent {
event_id: "" // INVALID: empty
event_type: EVENTHUB_TYPE_<VALID_TYPE>
source_service: "integration-service"
}
// Error: "EventHub event ID is not defined"
Type mismatch — rejected
EventHubEvent {
event_id: "550e8400-e29b-41d4-a716-446655440000"
event_type: EVENTHUB_TYPE_<TYPE_A> // Type A declared...
source_service: "integration-service"
<type_b_sub_event>: { ... } // ...but Type B sub-event provided
}
// Error: "EventHub type and sub event not matching"

Diagram

Notes

  • Implement idempotent processing — Use eventId (the message key) as a deduplication key. Store processed event IDs and skip duplicates. This is critical because Event Hub provides at-least-once delivery.

  • Pin proto artifact versions — Always use a specific version of the Event Hub proto artifact that matches Event Hub's deployment. Avoid version ranges or LATEST — they can introduce unexpected schema changes.

  • Handle unknown event cases gracefully — When processing the oneof event field, always include a default case in your switch statement. Teams may add new event types to the proto definition before updating your consumer.

warning

Event Hub forwards events as Protobuf binary without transformation. If teams deploy a proto schema change to Event Hub but not to a consumer, the consumer's Protobuf deserializer may fail on unrecognized fields or enum values. Always deploy schema updates to consumers before or simultaneously with Event Hub.

tip

The eventId field serves double duty: it is both the message key (guaranteeing same-partition ordering for the same event) and the unique identifier for idempotency. Build your deduplication logic around this field.

Next Step

Continue with Audit & Observability to learn how Event Hub audit logs are collected and how to monitor event processing with OpenTelemetry.

What deserializer should consumers use?

Consumers must use a Protobuf Deserializer. The deserializer configuration should reference the EventHubEvent class generated from the Event Hub proto artifact.

Can the same event be delivered more than once?

Yes. Event Hub provides at-least-once delivery. In rare edge cases (batch update failure after successful event bus send), Event Hub may deliver the same event again. Consumers must implement idempotent processing using eventId as the deduplication key.

Do consumers need to re-validate events?

No. Event Hub validates every event before writing to the outbox. Any message received from an event bus topic has already passed all validation rules. Consumers do not need to re-validate the structural invariants listed in this page.

How should consumers handle schema evolution?

Teams manage proto definitions through versioned artifacts. Backward-compatible changes (adding optional fields, new enum values) do not require consumer updates. Breaking changes require coordinated deployment. Always deploy schema updates to consumers before or simultaneously with Event Hub.