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, feed the dashboard counts, and register the built-in job templates in each new metalake, and you can register your own alongside them.
Quick start
-
Build a listener. Implement
EventListenerPluginand choose its dispatch mode. The chart has no value that puts a jar on the server classpath, so a listener of your own needs a custom server image that contains its jar. -
Register it by name. Add the name to the end of
gravitino.eventListener.namesand point{name}.classat the implementation. Replacing the list instead of extending it removes any listener already named there.The list has a dedicated chart value,
gravitino.eventListener.names, which defaults tosearch,dashboard-metrics. The chart writesclassentries only forsearchanddashboard-metrics, so the class of your listener goes undergravitino.additionalConfigItems.my-values.yamlgravitino:
eventListener:
names: "search,dashboard-metrics,{listener_name}"
additionalConfigItems:
gravitino.eventListener.{listener_name}.class: "{listener_class}" -
Apply the change and confirm the listener started. The Helm upgrade restarts the server pod. The listener is running once the pod is
Runningand its log containsStart event listener {listener_name}.Find started listenerskubectl exec -n {namespace} deploy/{release}-gravitino -c gravitino -- \
sh -c 'grep "Start event listener" /opt/gravitino/logs/$HOSTNAME/gravitino-server.log'A name in
gravitino.eventListener.nameswith no matchingclassentry makes the server throw at startup and exit, and so does a class that cannot be loaded or whoseinitthrows. On Helm the pod then crash-loops.
Events tab
Configure → Events in the UI shows the event settings from the chart's gravitino.conf ConfigMap.
It reads the ConfigMap, not the running server, and it is read only. Under the description
"Listeners notified when metadata changes." it shows:
- Queue capacity and Dispatcher join (seconds):
gravitino.eventListener.queueCapacityandgravitino.eventListener.dispatcherJoinSeconds, or3000and3when the ConfigMap does not set them. - Listeners: a table with Name, Type, and Mode columns, and a count of listeners below it.
The listener rows come from the ConfigMap, so they do not match what the server runs:
audit-logappears, with Type Built-in, whengravitino.audit.enabledistrue.- Every name in
gravitino.eventListener.namesappears with Type Custom, the chart's ownsearchanddashboard-metricsincluded. - Mode reads
ASYNC_ISOLATEDon every row, whatever the listener declares. builtin-job-template, which the server always registers, never appears.
The tab shows no queue depth and no count of dropped events. Dropped events show only in the server pod's log, as described in Queue behavior.
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 Iceberg REST service carry an Iceberg prefix, as in IcebergCreateTableEvent. Not every
operation defines all three. The full set of classes is in the
org.apache.gravitino.listener.api.event
package.
A request that produces no operation event still produces one event of its own: HttpRequestEvent
when it succeeds, and HttpRequestFailureEvent when it ends with a 4xx or 5xx status. A request
rejected with 401 before it reaches any operation is one of these. Both reach every listener, the
audit log included.
A pre-event handler that throws ForbiddenException stops the operation before it runs, but only
when the listener's mode is SYNC. From any other listener the exception is logged and the
operation goes ahead. An exception a listener throws while handling a post-event or a failure event
is logged and swallowed, so it never changes the result the client receives.
Inline listeners run inside the request, so the client waits for them. Asynchronous listeners receive the same events from a queue after the fact, as described in Queue behavior.
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. |
Built-in listeners
| Listener | Registered when | Delivery |
|---|---|---|
audit-log | gravitino.audit.enabled is true | Inline, on the request thread |
builtin-job-template | Always | Inline, on the request thread |
search | Named in gravitino.eventListener.names | Its own queue (ASYNC_ISOLATED) |
dashboard-metrics | Named in gravitino.eventListener.names | Its own queue (ASYNC_ISOLATED) |
Only search and dashboard-metrics go through a queue. The server registers audit-log and
builtin-job-template directly, without one, so they run on the request thread whatever mode they
declare. A slow audit log writer therefore slows every request.
Configuration
| Configuration item | Description | Default value |
|---|---|---|
gravitino.eventListener.names | Comma-separated listener names. | search,dashboard-metrics |
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 |
Set gravitino.eventListener.names through the chart value of the same name, and the others under gravitino.additionalConfigItems in my-values.yaml as quoted strings; see Set other server properties.
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 search index it is a change that search does not reflect until the object changes again. The audit log has no queue, so a full queue never costs it a record.
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.