Support multiple event listener plugins#2305
Support multiple event listener plugins#2305jdintruff wants to merge 1 commit intotrinodb:masterfrom
Conversation
|
Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please submit the signed CLA to cla@prestosql.io. For more information, see https://github.com/prestosql/cla. |
|
@cla-bot check |
|
The cla-bot has been summoned, and re-checked this pull request! |
There was a problem hiding this comment.
We should do this like the recent access control change, where each file name is listed. Unlike catalogs, there’s no concept of “instance name” used by Presto, so we can reference the files directly. See https://github.com/prestosql/presto/blob/master/presto-main/src/main/java/io/prestosql/security/AccessControlConfig.java and https://github.com/prestosql/presto/blob/master/presto-main/src/main/java/io/prestosql/security/AccessControlManager.java
There was a problem hiding this comment.
I updated the doc here to reflect the new conf changes
There was a problem hiding this comment.
Please model the loading code and logging after AccessControlManager
There was a problem hiding this comment.
I updated this to be more like the AccessControlManager
There was a problem hiding this comment.
I’m thinking we should catch exceptions and log a warning, so that one listener doesn’t affect others (especially since there is no defined order they will be invoked)
There was a problem hiding this comment.
Added a warning for when exceptions are thrown from the event listeners but I believe this would still allow event listeners to block one another
There was a problem hiding this comment.
Yes, being slow or hanging is a problem, but there's not much that can be done. We'd need separate executors for each listener with a fixed queue size that eventually discards events.
58876c2 to
63805ff
Compare
63805ff to
d9aaf09
Compare
electrum
left a comment
There was a problem hiding this comment.
Apologies for the late follow up. A few minor comments, otherwise ready to go. Thanks for implementing this feature.
| private final List<File> configFiles; | ||
| private final Map<String, EventListenerFactory> eventListenerFactories = new ConcurrentHashMap<>(); | ||
| private final AtomicReference<Optional<EventListener>> configuredEventListener = new AtomicReference<>(Optional.empty()); | ||
| private final AtomicReference<List<EventListener>> configuredEventListeners = |
There was a problem hiding this comment.
This wrapping shouldn't change
|
|
||
| if (eventListenerFactories.putIfAbsent(eventListenerFactory.getName(), eventListenerFactory) != null) { | ||
| throw new IllegalArgumentException(format("Event listener '%s' is already registered", eventListenerFactory.getName())); | ||
| throw new IllegalArgumentException( |
| checkState(!isNullOrEmpty(name), "Access control configuration %s does not contain '%s'", configFile, NAME_PROPERTY); | ||
|
|
||
| setConfiguredEventListener(name, properties); | ||
| List<EventListener> eventListeners = |
There was a problem hiding this comment.
Formatting nit: don't wrap the assignment, but do wrap the stream operations. Also, prefer the immutable collectors.
List<EventListener> eventListeners = configFiles.stream()
.map(this::createEventListener)
.collect(toImmutableList());| } | ||
| configFiles = ImmutableList.of(CONFIG_FILE); | ||
| } | ||
|
|
There was a problem hiding this comment.
Just to be safe, let's add an AtomicBoolean so that we can't accidentally load twice
checkState(loading.compareAndSet(false, true), "Event listeners already loaded");| log.info("-- Loaded event listener %s --", name); | ||
| String name = properties.remove(EVENT_LISTENER_NAME_PROPERTY); | ||
| checkArgument(!isNullOrEmpty(name), "EventListener plugin configuration for %s does not contain %s", configFile, | ||
| EVENT_LISTENER_NAME_PROPERTY); |
| try { | ||
| listener.queryCompleted(queryCompletedEvent); | ||
| } | ||
| catch (Exception e) { |
There was a problem hiding this comment.
This should be RuntimeException since the event listener doesn't throw any checked exceptions. However, I'm thinking we should make this Throwable. While we hope plugins don't throw Error, if they do, there's nothing we can do, so we might as well log it and continue.
Same for the other events.
| { | ||
| configBinder(binder).bindConfig(EventListenerConfig.class); | ||
| binder.bind(EventListenerManager.class).in(Scopes.SINGLETON); | ||
| newExporter(binder).export(EventListenerManager.class).withGeneratedName(); |
There was a problem hiding this comment.
No need to add this since EventListenerManager doesn't have any @Managed annotations.
| extends EventListenerManager | ||
| { | ||
| private final AtomicReference<Optional<EventListener>> configuredEventListener = new AtomicReference<>(Optional.empty()); | ||
| private final AtomicReference<Set<EventListener>> configuredEventListeners = new AtomicReference(new HashSet()); |
There was a problem hiding this comment.
Use new HashSet<>() so that it's not a raw type.
We don't need to change this class at all, since it still only supports a single event listener. If we want to change it, we should make it add each new listener (instead of overwriting the set). However, I feel changing the test implementation is somewhat unrelated to the rest of the PR (which is allow multiple listeners for the main server).
| @Test | ||
| public void testDefaults() | ||
| { | ||
| ConfigAssertions.assertRecordedDefaults(ConfigAssertions.recordDefaults(EventListenerConfig.class) |
There was a problem hiding this comment.
Nit: static import all the ConfigAssertions methods
| .build(); | ||
|
|
||
| EventListenerConfig expected = new EventListenerConfig() | ||
| .setEventListenerFiles("a,b,c"); |
There was a problem hiding this comment.
Call the List version of the setter in the test, in order to verify the splitting workers correctly. (the value from the map will go through the string version)
|
some conflicts @jdintruff |
|
@jdintruff just wanted to ask if you plan to look at this in near future. |
|
@jdintruff If you don't have time to work on this, I can take over this. |
|
Replaced with #3128 |
Per #2299 it would be helpful to be able to declare both multiple instances of the same event listener as well as multiple instances of different event listeners. I've tested this locally with two simple logging plugins but I still need to write proper tests.