Events
Gravitino emits an event around every metadata operation, and event listeners receive them. A listener is how another system follows changes to the catalog without polling it. The server itself uses listeners to write the audit log, keep the search index current, and feed the dashboard counts, and you can register your own alongside them.
The UI lists the listeners registered on the server, with the dispatch mode of each, and the two queue settings that govern asynchronous delivery.
Quick Start
1. Build a listener. Implement EventListenerPlugin, choose its dispatch mode, and put the jar
on the server classpath.
2. Register it by name. Add the name to the end of gravitino.eventListener.names and point
{name}.class at the implementation. Replacing the list instead of extending it removes any
listener already named there.
gravitino.eventListener.names = {existing_names},{listener_name}
gravitino.eventListener.{listener_name}.class = {listener_class}
3. Restart the server and confirm the listener appears in the UI. A name without a matching class stops the server from building that listener.
Events
Each operation emits up to three events: a pre-event before it runs, a post-event after it
succeeds, and a failure event after it throws. The names follow the operation, so createTable
produces CreateTablePreEvent, CreateTableEvent, and CreateTableFailureEvent. Operations served
by the Gravitino IRC endpoint carry an Iceberg prefix, as in IcebergCreateTableEvent.
A pre-event handler that throws ForbiddenException stops the operation before it runs, so a
synchronous listener can act as a veto rather than only an observer.
Listeners
Dispatch Modes
Every listener declares how its events reach it.
| Mode | Behavior |
|---|---|
SYNC | Called inline, before the operation's result reaches the client. A slow listener slows every request. |
ASYNC_ISOLATED | Called from a queue and dispatcher thread of its own, so one slow listener cannot hold up another. |
ASYNC_SHARED | Called from one queue and dispatcher shared by every listener in this mode, so a slow listener delays the others on the same queue. |
The listeners the server registers for itself all run ASYNC_ISOLATED, so none of them adds
latency to a request.
Configuration
| Configuration Item | Description | Default Value |
|---|---|---|
gravitino.eventListener.names | Comma-separated listener names. | (empty) |
gravitino.eventListener.{name}.class | Class of the listener registered under {name}. | (none) |
gravitino.eventListener.{name}.{key} | Any other property under a listener's name, passed to that listener unchanged. | (none) |
gravitino.eventListener.queueCapacity | Events each asynchronous queue holds before it starts dropping them. | 3000 |
gravitino.eventListener.dispatcherJoinSeconds | Seconds shutdown waits for each dispatcher thread to exit. | 3 |
Queue Behavior
Each ASYNC_ISOLATED listener has its own queue of queueCapacity events, and all ASYNC_SHARED
listeners share one more. When a queue is full, a new event is dropped rather than waited for, so
the operation that produced it is never slowed. The server logs a warning with the number dropped,
at most once a minute per queue.
A dropped event never reaches its listener. For the audit log that is a gap in the record, and for the search index it is a change that search does not reflect until the object changes again. Warnings about dropped events mean a listener cannot keep up, and the fix is a faster listener or a larger queue.
At shutdown the server stops each dispatcher and waits up to dispatcherJoinSeconds for the
thread to exit. Events still queued at that point are dropped and counted in a warning, so a
listener that must see every event needs its own durable delivery rather than relying on the
queue.