Skip to content

Events and change notifications

Kessel publishes change events whenever resources are created, updated, or deleted. These events enable downstream services to react to changes in real-time, build materialized views, trigger workflows, or maintain synchronized state across distributed systems.

Events are published to Kafka topics with at-least-once delivery guarantees. Each resource write produces events atomically using the transactional outbox pattern, ensuring consistency between database state and published events even in the face of failures or restarts.

This document explains how Kessel’s eventing system works, what events are published, and the delivery guarantees you can rely on.

Kessel events use a JSON structure with fields inspired by CloudEvents attributes, but are not CloudEvents 1.0 compliant. The event structure provides event metadata (type, id, time, subject) and a data field containing the resource payload.

Event envelope fields:

  • specversion: Always "1.0" (indicates format version)
  • type: Event type in the format redhat.inventory.resources.{resource_type}.{operation}
  • source: Reserved for future use (currently empty string)
  • id: Unique event identifier (UUID)
  • time: Event timestamp in ISO 8601 format
  • datacontenttype: Always "application/json"
  • subject: Resource path (e.g., /resources/k8s_cluster/{resource_id})
  • data: Event payload (nested object with resource/relationship data)

Example event structure:

{
"specversion": "1.0",
"type": "redhat.inventory.resources.k8s_cluster.created",
"source": "",
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"time": "2026-05-14T15:30:00Z",
"datacontenttype": "application/json",
"subject": "/resources/k8s_cluster/abc-123",
"data": {
"metadata": { ... },
"reporter_data": { ... },
"resource_data": { ... }
}
}

This format provides structured event metadata and payload, making it straightforward to route, filter, and process events in downstream consumers.

Kessel publishes resource events when resources are created, updated, or deleted via ReportResource or DeleteResource.

Event type pattern: redhat.inventory.resources.{resource_type}.{operation}

Operations:

  • created — Resource reported for the first time
  • updated — Existing resource representation changed
  • deleted — Resource marked as deleted (tombstone)

Subject format: /resources/{resource_type}/{resource_id}

Payload structure (data field):

{
"metadata": {
"id": "resource-uuid",
"resource_type": "k8s_cluster",
"org_id": "org-123",
"workspace_id": "workspace-456",
"created_at": "2026-05-14T10:00:00Z",
"updated_at": "2026-05-14T15:30:00Z",
"deleted_at": null,
"labels": []
},
"reporter_data": {
"reporter_type": "acs",
"reporter_instance_id": "acs-central-prod",
"local_resource_id": "cluster-789",
"api_href": "https://acs.example.com/v1/clusters/cluster-789",
"console_href": "https://console.redhat.com/openshift/details/cluster-789",
"reporter_version": "4.2.1"
},
"resource_data": {
"name": "production-us-east",
"provider": "aws",
"region": "us-east-1",
"version": "4.15.0"
}
}

Resource events are published to the Kafka topic outbox.event.kessel.resources.

Partitioning: Events for the same resource ID are routed to the same Kafka partition (using resource ID as the message key), ensuring ordered processing per resource within a single consumer.

Kessel provides reliable event delivery with the following semantics:

At-least-once delivery — Events may be delivered more than once in certain failure scenarios. Consumers should implement idempotent processing to handle duplicate events safely. Kessel’s internal consumer uses OPERATION_TOUCH (upsert) semantics when writing to SpiceDB, ensuring duplicate events do not cause errors.

Atomic publication — Each ReportResource or DeleteResource operation produces events atomically using the transactional outbox pattern. If the write succeeds, the event is guaranteed to be published. If the write fails, no event is published.

Durability — Once an event is published to Kafka, it is durably stored and can be consumed by multiple subscribers independently.

Ordering per resource — Events for the same resource ID are routed to the same Kafka partition, ensuring ordered processing per resource within a single consumer.

These guarantees mean you can rely on the event stream as an authoritative record of all changes without needing to poll the API or implement your own change tracking, as long as your consumer handles duplicate events correctly.

Events and consistency are tightly coupled in Kessel’s architecture. The same event stream that external consumers subscribe to also drives updates to the authorization graph.

How it works:

  1. ReportResource writes the resource data
  2. An event is published to the event stream
  3. Kessel processes the event and updates the authorization graph
  4. The consistency token is updated upon successful processing

This means the consistency token visible in IMMEDIATE mode checks reflects how far Kessel has progressed through the event stream.

See Consistency model for details on how consistency modes interact with event processing.