-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(notifications): implement vertx event bus to listen for notifications emitted #1020
feat(notifications): implement vertx event bus to listen for notifications emitted #1020
Conversation
I just meant to define some interface like
It's the nature of a pub/sub system or an event bus to send out messages broadly, and on the other end try to listen only for messages you're likely to care about. In this case the event bus "address", which for us is the notification category, fills that role. Beyond that, the message consumer may need to do some further check to determine if the message is something it does care about, which you've handled here.
Well, Vertx isn't an inversion-of-control framework. Dagger gives us dependency injection, which is generally a kind of inversion of control. For that, Dagger's own docs are pretty good. DI isn't limited to backend development either, in fact Dagger is probably much more commonly used in mobile development than it is in backend development. |
interface NotificationListener<T> {
Set<String> categories();
void onMessage(String category, T message);
}
class NotificationPublisher {
Vertx vertx;
Set<NotificationListener> listeners;
NotificationPublisher() {
listener.forEach(listener -> {
listener.categories().forEach(category -> {
vertx.eventBus().consumer(category).handler(message -> listener.onMessage(category, message));
});
});
}
<T> void send(String category, T message) {
vertx.eventBus().publish(category, message);
}
}
class NotificationModule {
@Binds @IntoSet abstract NotificationListener bindTestListener(TestListener listener);
// in Cryostat we already have the NotificationFactory that is something like this
@Provides static NotificationPublisher provideNotificationPublisher(Vertx vertx, Set<NotificationListener> listeners) {
return new NotificationPublisher(vertx, listeners);
}
}
class TestListener implements NotificationListener<Foo> {
@Override
public Set<String> categories() {
return Set.of("cat", "dog");
}
@Override
public void onMessage(String category, Foo message) {
System.out.println(String.format("[%s]: %s", category, message.asJson()));
}
}
class TestSender {
NotificationPublisher publisher;
void hello() {
publisher.send("dog", new Foo(1234));
}
} That's a little sloppy, but I hope it gets the point across. This way only the publisher class actually knows anything about Vertx, and it uses it in a very isolated fashion. The listeners don't need to add a Vertx dependency injection, and the only notification-related tests needed on the |
src/main/java/io/cryostat/net/reports/ActiveRecordingReportCache.java
Outdated
Show resolved
Hide resolved
Not sure how to bind the Also may be better ways to parse the Ignoring tests, thoughts on the structure? |
src/main/java/io/cryostat/messaging/notifications/NotificationListener.java
Outdated
Show resolved
Hide resolved
src/main/java/io/cryostat/net/reports/ActiveRecordingReportCache.java
Outdated
Show resolved
Hide resolved
Not sure exactly what you mean here.
Does this example help answer the question at all?
Why? |
Sorry, I meant that the
Uh, I think I was thinking like generally, since Notifications have different structures, it may be difficult to extend the parsing to all kinds, but I realize that Notifications are all generally the same structure of |
I see. Though, why does the
Makes sense. Yea, I think your insight that our notifications all have a consistent form of Meta and Message, where both of those are also generally just flat map structures, is the key. The |
Is this sort of what it should look like? Sorry, I'm sort of having trouble adapting this to the example you linked, mostly because of the |
Yea, that looks like it's along the right lines. Forcing the type to be I think I would rather leave the |
Before tests and removing prints, thoughts? |
… to JSON.parse() notification message coming from notification publisher singleton which runs consumers on all listeners on constructor init
…cations get passed throught the socket, refactored, used jackson ObjectMapper
a12f2c0
to
cc04f6a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, nice and clean now. Just a few more notes.
src/main/java/io/cryostat/net/reports/ActiveRecordingReportCache.java
Outdated
Show resolved
Hide resolved
src/main/java/io/cryostat/messaging/notifications/NotificationSource.java
Show resolved
Hide resolved
src/main/java/io/cryostat/messaging/notifications/NotificationListener.java
Outdated
Show resolved
Hide resolved
src/main/java/io/cryostat/net/reports/ActiveRecordingReportCache.java
Outdated
Show resolved
Hide resolved
…, removed useless duplicate method invalidateCacheEntry
…dule, fixed tests, everything seems good to go now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I have some further refactoring ideas in mind but I think I'll just play around with that myself after we get this merged, and see what I end up liking.
Fixes #921
So far I've implemented the feature very shallowly, thoughts on what needs to be done on a larger scale? I'm not quite sure what you meant by the NotificationListener thin wrapper feature. Right now, every consumer handlers trigger on any DeleteActiveRecording Notification, and that might not be good so I was thinking maybe passing the RecordingDescriptor key when publishing the notification to the address and then each consumer just if else checking the message? Is that why we need a wrapper around a Notification to better facilitate this?
Also, would you recommend resources for understanding the module, provides, component, injection design patterns of Dagger, Vertx and other inversion of control frameworks? This part of back-end development is definitely something I would like to get more comfortable with along my time on the project.