Skip to content
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

Add new ClusteredApplicationEvent extends ApplicationEvent with multicaster that uses JMS to distribute messages [SPR-10616] #15244

Closed
spring-projects-issues opened this issue Jun 1, 2013 · 3 comments
Assignees
Labels
in: core in: messaging status: declined type: enhancement

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Jun 1, 2013

Nick Williams opened SPR-10616 and commented

#8322 "ApplicationEvent across JVM using JMS" made the same request but with no suggested details. That request was filed 6 years ago and closed automatically "through a selective bulk update, as part of a larger effort to better manage unresolved issues" (according to the comment).

Shahzad Bhatti describes in his blog post "Integrating Spring Event Notification with JMS" a pattern for using Spring's ApplicationEvent and ApplicationListener classes to leverage JMS and form distributable messages/events.

I have myself implemented two different approaches to achieve clustered events using Spring's ApplicationEvent. Both involved a ClusteredApplicationEvent extends ApplicationEvent that served as a marker interface for ApplicationEvent s that should be distributed instead of simply multicast on the JVM. The ClusteredApplicationEvent had a rebroadcasted flag that indicated whether an event broadcast to the application had just been multicast locally or had been received from another server (on receiving an event from the cluster the rebroadcasted flag was marked true before multicasting it). This kept the events from rebroadcasting recursively. One approach used a shared database to persist events to and poll for events from other nodes. The other approach used a socket connection to stream serialized events between nodes (each node had a connection to every other node). These have both been reliable patterns that have worked for me for a couple years now.

Finally, I have seen several other inquiries/ideas/suggestions online throughout the years to make ApplicationEvent s distributable in a cluster.

Here is my suggestion:

Create generic ClusteredApplicationEvent

Any time the developer wishes a message to be sent to the entire cluster as opposed to just the local JVM, he would make the event extend this class. Alternatively, this class could be called something else, like DistributedApplicationEvent, DistributableApplicationEvent, etc. I would argue against using JMS in the name, so that future/custom non-JMS implementations can also utilize this class.

package org.springframework.context.event;

public abstract class ClusteredApplicationEvent extends ApplicationEvent {
    private final Serializable serializableSource; // original source is transient, won't serialize
    private boolean rebroadcasted;

    public ClusteredApplicationEvent(Serializable source) {
        super(source);
        this.serializableSource = source;
    }

    final boolean isRebroadcasted() {
        return this.rebroadcasted;
    }

    final void setRebroadcasted() {
        this.rebroadcasted = true;
    }

    @Override
    public Serializable getSource() {
        return this.serializableSource;
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        this.source = this.serializableSource; // restore transient value
    }
}

Create an abstract ClusteredApplicationEventMulticaster

This class would take care of common tasks that are related to all clustered
multicasters, such as not publishing ApplicationEvent s that aren't ClusteredApplicationEvent s to the cluster (only locally), and not publishing ClusteredApplicationEvent s whose rebroadcasted flag was true to the cluster (only locally). Spring Framework users would have to configured some implementation of ClusteredApplicationEventMulticaster for ClusteredApplicationEvent s to work. Otherwise, ClusteredApplicationEvent s would be treated like any other events and just multicast locally.

package org.springframework.context.event;

public abstract class ClusteredApplicationEventMulticaster extends SimpleApplicationEventMulticaster {
    // ...
    @Override
    final public void multicastEvent(ApplicationEvent event) {
        try {
            super.multicastEvent(event);
        } finally {
            try {
                if(event instanceof ClusteredApplicationEvent &&
                    !((ClusteredApplicationEvent)event).isRebroadcasted()) {
                    this.publishClusteredEvent((ClusteredApplicationEvent)event);
                }
            } catch(Exception e) {
                log.error("Failed to broadcast distributable event to cluster.");
            }
        }
    }

    protected abstract void publishClusteredEvent(ClusteredApplicationEvent event);

    final protected void handleReceivedClusteredEvent(ClusteredApplicationEvent event) {
        event.setRebroadcasted();
        this.multicastEvent(event);
    }
    // ...
}

Create a JmsApplicationEventMulticaster in the spring-jms project

This multicaster will be the only clustered multicaster that Spring supports initially, though users will be free to implement their own. It would obviously expect some form of Spring JMS configuration in order to work, and would throw an exception on initialization if a JMS configuration did not exist for it to use. It would implement whatever other interfaces were necessary to support listening for JMS events (I'm unfamiliar with this API right now) and would call handleReceivedClusteredEvent when it received those JMS events.

package org.springframework.jms;

public class JmsApplicationEventMulticaster extends ClusteredApplicationEventMulticaster implements ... {
    // ...
    protected void publishClusteredEvent(ClusteredApplicationEvent event) {
       // ...
    }
}

Thoughts?


Affects: 4.0 M1

Issue Links:

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jun 25, 2013

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jun 25, 2013

Nick Williams commented

I haven't, no. I'm not even sure what Spring Integration is...

I'll have to do some research this weekend.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 9, 2013

Phil Webb commented

I think this kind of feature is best suited to Spring Integration so marking as "Won't Fix" for now.

@spring-projects-issues spring-projects-issues added status: declined in: messaging type: enhancement in: core labels Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core in: messaging status: declined type: enhancement
Projects
None yet
Development

No branches or pull requests

2 participants