Skip to content

Conversation

@vchag
Copy link

@vchag vchag commented Nov 3, 2025

These changes were created to address concerns raised in Issues #2630

What changes were proposed in this pull request?

  1. Streamlining Event-to-JSON Serialization:
    The previous architecture involved a redundant, two-step conversion process: events were transformed into intermediate Maps by an abstract class, and only then was the resulting map serialized into JSON (as seen in AwsCloudWatchEventListener).
    Since Jackson JSON is our chosen serialization format, we've removed this unnecessary intermediate mapping step. We introduced Jackson Mixins to provide native JSON serialization support directly on the event objects. This refactoring simplifies the serialization pipeline from:
    Event -> Map -> JSON
    to
    Event -> JSON

  2. Introduces AllEventsForwardingListener, a generic event listener designed to automatically receive and forward all Polaris events without requiring explicit event-type configuration.

  3. Introduces polaris.event-listener.aws-cloudwatch.event-types property: This property introduces a configurable event filter for the AWS CloudWatch event listener.
    It defines which Polaris event types should be serialized and forwarded to CloudWatch Logs.

Why are the changes needed?

Does this PR introduce any user-facing change?

How was this patch tested?

CHANGELOG.md

Copy link
Contributor

@adutra adutra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for re-opening a PR @vchag , this is now looking much better.

# polaris.event-listener.aws-cloudwatch.log-stream=polaris-cloudwatch-default-stream
# polaris.event-listener.aws-cloudwatch.region=us-east-1
# polaris.event-listener.aws-cloudwatch.synchronous-mode=false
# polaris.event-listener.aws-cloudwatch.event-types= // the absence of this property would result if processing all Polaris event types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# polaris.event-listener.aws-cloudwatch.event-types= // the absence of this property would result if processing all Polaris event types.
# polaris.event-listener.aws-cloudwatch.event-types= // the absence of this property would result in processing all Polaris event types.

executorService = Executors.newSingleThreadExecutor();

// Build the test mapper and apply the same customizations Quarkus would
objectMapper = new ObjectMapper();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could be a final field.

AwsCloudWatchConfiguration config,
Clock clock,
PolarisIcebergObjectMapperCustomizer customizer) {
PolarisIcebergObjectMapperCustomizer customizer,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to pass the customizer, the customizer will be invoked for you by Quarkus. Just inject the object mapper.

protected abstract void handle(PolarisEvent event);

/** Optional filter (config-based). Default: handle all. */
protected boolean shouldHandle(Object event) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
protected boolean shouldHandle(Object event) {
protected boolean shouldHandle(PolarisEvent event) {

Comment on lines +90 to +94
this.listenToAllEvents =
config.eventTypes().isEmpty()
|| config.eventTypes().map(Set::isEmpty).orElse(true)
|| config.eventTypes().get().stream().anyMatch(e -> e == PolarisEvent.class);
this.allowedEventTypes = listenToAllEvents ? Set.of() : Set.copyOf(config.eventTypes().get());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think we can simplify a bit:

    this.allowedEventTypes = config.eventTypes().orElse(Set.of());
    this.listenToAllEvents =
        allowedEventTypes.isEmpty()
            || allowedEventTypes.stream().anyMatch(c -> c == PolarisEvent.class);

if (this.listenToAllEvents) {
return true;
}
Class<? extends PolarisEvent> actualType = polarisEvent.getClass();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this is probably a bit inefficient under a high load. Switching to event type IDs should help because the lookup would be faster when using an EnumSet.

}

@PostConstruct
void verifyMapper() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary.

import org.apache.polaris.service.events.PrincipalsServiceEvents;

/**
* Base class for event listeners that with to generically forward all {@link PolarisEvent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Base class for event listeners that with to generically forward all {@link PolarisEvent
* Base class for event listeners that wish to generically forward all {@link PolarisEvent

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants