Spring Cloud Bus - Custom Event Received but not handled by Event Handler - spring-cloud-bus

I am using Spring Cloud Bus (1.2.1.RELEASE, Camden.SR2). I have a custom event (call it CustomEvent) that I have created and registered via #RemoteApplicationEventScan as well as a custom AbstractBusEndpoint implementation to publish the event. I am able to publish events to the bus just fine.
My remote application receives the event and acknowledges (I verified this using the trace endpoint). I have verified via debugging that the CustomEvent is published via the ApplicationEventPublisher provided in BusAutoConfiguration#acceptRemote. I have a bean with an event handler in my remote application (I have this auto-configured into all of my micro-services):
#Component
public class EventListener {
#EventHandler(CustomEvent.class)
public void handleCustomEvent(CustomEvent event) {
..
}
}
Despite this, the event handler will not receive the event. I traced within the AbstractApplicationEventMulticaster class and despite my bean being created (verified via beans endpoint), the listener is not in the list of ApplicationListeners retrieved by ListenerRetriever. I do see the BusAutoConfiguration.acceptLocal listener in this list, but not my custom listener.
This event handler is also registered on the source application (the one I am accessing the bus endpoint from to initiate the event). The custom listener receives the event in this application, but not the remote application.
Essentially, both applications are configured the exact same except one is configured to send the CustomEvent using an implementation of AbstractBusEndpoint.
I am out of ideas of where else to look within the Spring code to debug this problem. If anyone has a thread they can lead me on it would be appreciated.

I've come up with the exact same problem, and debugging it revealed that ApplicationListener which handles the custom remote event not returned among candidate listeners within ApplicationEventMulticaster due to eventType was loaded by two different classloaders, one of them was devtools related classloader. Removing devtools dependency from classpath simply resolved issue for me.

Related

Endpoint startup notification in Liberty

Using Microprofile Liberty server, I need to notify another service on startup that will callback my service on https endpoint. By the way the https endpoint is not always started and inbound service may receive some connection errors.
Options I could imagine are: retry on other service or verify https availability doing rest calls before notifying other service.
Is there any built in way to be notified that endpoint is started or available using MBean notification or CDI event ?
I'm not totally clear on the use case, but it seems like you need to perform an operation (attempting to call another service) on startup? If that's the case, you could try using a CDI bean that listens to the startup event like this:
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
#ApplicationScoped
public class StartupNotification {
public void notifyOtherService(#Observes #Initialized(ApplicationScoped.class) Object context) {
// this will be invoked on application startup
// run code here to notify the other service on startup
}
}

Is it possible for my Spring EventListener to wait for 2 events to progress?

I have a SpringBoot application and have to connect to a websocket server to receive messages, which my application then processes internally using an inbuilt FinitStateMachine (FSM).
What I want is to start the connect() call to the websocket server only after:
my spring application has initialized
my FSM builder has completed the build() call
I have used Spring's ApplicationEventPublisher to publish a custom event (FSMInitializedEvent) when my FSM is built. And the code which initiates connection to websocket server waits for this custom event, but I want my websocket connector code to ALSO wait for Spring's ApplicationReadyEvent. Is there a neat way to do this?
From my FSM's build():
applicationEventPublisher.publishEvent( new FSMInitializedEvent() );
Within my WebSocket connector class:
#EventListener(FSMInitializedEvent.class) <-- HERE i want to listen for this other event too before progressing - ApplicationReadyEvent.class
public void init() {
// code to initiate the connection
}
I could programmatically handle this but looking for some ready to use elegant solution. Also, my question is different what's been suggested here: Use #EventListener annotation on multiple events in Spring, as I want my listener to wait for multiple events to have happened as a precondition, before proceeding.

Why does the ConfigurationAdmin specification use its own eventing mechanism, as opposed to the EventAdmin?

I want to understand why the ConfigurationAdmin specification defines its own mechanism for dispatching events, instead of using the EventAdmin specification, which is also defined in the OSGi Compendium.
The ConfigurationAdmin specification mentions that it will send ConfigurationEvents to ConfigurationListeners registered in the service registry.
Listener for Configuration Events. When a ConfigurationEvent is fired, it is asynchronously delivered
to all ConfigurationListeners.
ConfigurationListener objects are registered with the Framework service registry and are notified
with a ConfigurationEvent object when an event is fired.
ConfigurationListener objects can inspect the received ConfigurationEvent.
This seems like it would be a fine candidate for the EventAdmin, given that the properties of the ConfigurationEvent are all primitive.
val event: Event = Event(Hashtable(mapOf<String, Any>(
"type" to CM_UPDATED,
"service.factoryPid" to "someFactoryPid.guid",
"service.pid" to "somePid.guid"
)))
#Component
class ConfigurationListener : EventHandler {
override fun handleEvent(event: Event) {
// ...
}
}
I'm designing some services which would make use of some sort of event handling mechanism. The choices I think I have are using the EventAdmin (provided in the Compendium), and rolling my own (like the ConfigurationAdmin).
I'd like to know what design decision was made that led the OSGi Alliance to create a separate event mechanism for the ConfigurationAdmin, instead of the already created event mechanism, provided by the EventAdmin, and if I need to consider the same factors when selecting my event mechanism.
It seems like duplicated work.
The EventAdmin can send events synchronously or asynchronously (sendEvent and postEvent), and already provides an interface to responding to events (EventHandler).
The ConfigurationAdmin sends ConfigurationEvents asynchronously or synchronously depending on the the interface used to respond to the event(ConfigurationListener, SynchronousConfigurationListener), rather than the method called.
One possibility I'd considered was that the OSGi Alliance didn't want to make the services defined in the Compendium, depend on other Compendium services, based on the fact that the ConfigurationAdmin has no problem depending on the Service registry, which is defined in Core.
This seems to line up in my mind with the understanding that services are not guaranteed to exist at runtime; therefore making ConfigurationAdmin depend on EventAdmin would equate to "You cannot use this optional service (ConfigurationAdmin) unless this other optional service (EventAdmin) is guaranteed to be in the runtime as well" which is kind of contradictory.
There are several reasons:
Configuration Admin was designed before Event Admin
A type safe event interface like Configuration Admin is easier to use than using properties
As you figured out, it is not nice if services depend on each other. Implementations should be able to freely chose services and not be artificially constrained.

Spring Cloud Stream - Output Messages from EventListener

I'm trying to utilize the #DomainEvents mechanism provided by Spring Data to publish Events with Spring Cloud Stream (Spring Boot 2.0.0.M7 and Finchley.M5). I have a two-part question.
Why does SendTo not work on EventListeners?
Is there a better way to accomplish this?
The DomainEvent is being created and sent to the EventListener without issues. The problem is that the SendTo mechanism didn't seem to be working. The first method below would trigger, but not forward the message. Manually building the Message and sending it as shown in the second method works correctly.
#Async
#TransactionalEventListener
#SendTo(Sink.Output)
StreamedEvent handleEventWithSendTo(MyEvent event) {
// handle and create event
}
#TransactionalEventListener
void handleEvent(MyEvent event) {
// handle and create event
sink.output().send(MessageBuilder.withPayload(payload).build())
}
The call-out in the Spring Cloud Stream docs shows using SendTo on a StreamListener, which is not quite the same thing as an EventListener, but I thought it may work.
For the second part, using DomainEvents requires the service code persisting the Entity to know about the event (to either call registerEvent directly or some method on the Entity which represents the event). I was curious if using the Spring Data callback hooks (e.g. PreUpdate, PostUpdate) would be better. Or if there was a better way all together.

Capture Spring Session Destroy Event without registering the HttpSessionEventPublisher Listener

I wanted to perform some clean-up activity during Spring Session destroy (logout and timeout) and tried following the solution provided at this thread
but what made me curious is that, my application is a Spring Boot application and I didn't have to register the HttpSessionEventPublisher Listener , i just implemented the ApplicationListener interface and used the onApplicationEvent() method to capture the SessionDestroyEvent.
My question is, How did my code work without registering this listener
?
here is the answer from the Spring Session documentation itself
http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent
If you are using #EnableRedisHttpSession the SessionMessageListener and enabling the necessary Redis Keyspace events is done automatically. <<

Resources