Transparent CDI Events Distribution in a Cluster Environment via Metaprogramming
In my opinion, one of the great features of the JavaEE/Jakarta EE programming model is the CDI event mechanism.
But how this mechanism works in a cloud environment? Have you ever wondered what you can achieve if you are able to fire a CDI event on one machine and observe it on the other node? What if I tell you that we achieved this in almost a transparent way?
These post series are the descriptions of the inventions that I’m proud as a Computer Scientist. I talk about the decisions that I made and the steps I took to figure out what to do for these contributes and then do them.
Most of these contributions are the result of long conversations between me and the awesome members of Foundation Team (especially my friend and architect Alex Porcelli).
On Business Central (web tooling for Drools and jBPM projects) we make extensive use of the CDI programming model.
With Errai project we take the CDI programming model even further because Errai allows us to observe CDI events on the browser. So basically we have the same programming model working on client and backend of our application.
For instance, when we fire a NewProjectEvent on the backend of the platform, the same event is observed to all clients (browsers) connected (in order to quickly update the UI).
I’ll talk more about this on other blog posts but we are gradually moving Business Central to a cloud-ready architecture. This movement gave us an interesting problem:
“Having the same event programming model on backend and frontend save us a lot of time and CDI proves himself as a great way to deal with events in a monolith. Is it possible to extend the same model to the cloud? Can an event fired on one node be triggered to all other nodes and, via Errai CDI, to all connected clients in all nodes?”
As I already mentioned, IMO one of the great features of the JavaEE/Jakarta EE programming model is the CDI event mechanism. This model is one of the cleanest ways to decouple your applications.
However, this mechanism was designed to work in a single instance mode and doesn’t fit well for clustered environments use case. Basically, there is no way to observes an event fired in another machine in the cluster, requiring to use some other event technology and event manual translation.
The main goal of this invention is to extend the CDI event mechanism to a clustered environment, making easy and almost transparent for the users firing an event on one node and observes it on another node. But how?
Metaprogramming to the rescue
First, let’s create a new annotation called Clustered and let’s add it for the events that we want to propagate on the cluster.
Now, we can add it for an event:
Our users fires this event has a regular CDI event.
Behind the scenes, what our invention does:
- Observe all CDI events and check if a CDI event object type has @Clustered annotation [check the code]:
2. If this event has @Clustered annotation, we serialised it and sent a serialised cluster message with all event data. (on Business Central we use AMQ/Artemis for this) [check the code]:
3. In each other node, we receive this event, deserialise it and fire as a regular CDI event (reproducing it): [check the code]
So basically, what my invention do is to observe all CDI events and if a CDI event object type has @Clustered annotation, we sent a serialised cluster message with all event data, deserialise on other nodes and regenerate a new CDI event.
Using that invention doesn’t matter if the event was fired on the local instance or fired in other nodes because all CDI observables will receive the same event data, making the same CDI event programming model that works on a single instance works almost transparently on cloud environments.
If you are curious about the full details, you can take a look on the full PR of this solution.
In the end, I was really happy when I figure out this simple and elegant solution.
As I already mention with this invention our team are able to use the CDI programming model to distribute events in single node and in cluster environments, reducing the complexity of our codebase.
A future improvement would be to use the annotation processing framework in order to generate specific observers instead of observing all cdi events. This could be a good and fun contribution to our codebase and if you are interested ping me!
Thanks for reading! I hope this could be useful for you — or just fun to read ;) ! 💖