Catch login and join group event in Kafka consumer - spring

I am building Spring application for consume data from kafka. It successfully gets messages through #KafkaListener methods and I can receive some events by adding
#EventListener
public void handleKafkaConsumerEvent(KafkaEvent event) {
log.info("Kafka event " + event.toString())
}
But now I want to receive events about login (in log file it is like "o.a.k.c.s.authenticator.AbstractLogin : Successfully logged in." records) and (re)join to group events (in log file it is like "o.a.k.c.c.internals.AbstractCoordinator : [Consumer clientId=consumer-2, groupId=test_app] (Re-)joining group") events.
Is it possible to catch that events?

No; those log entries are made by the kafka-clients directly, and are not related to Spring, so Spring can't generate events for them.

Related

Set MDC properties only for rabbitmq events

I want to apply filters to log only for rabbit events using MDC properties.
And set trace Id && correlation id from the event header.
I already have a RequestResponseLoggingFilter which is used for setting the tenant Id.
I am not sure how to trigger this filter only for async rabbit events.
If you are using a MessageListener or #RabbitListener you can add a MessagePostProcessor to the listener container (or listener container factory, respectively) in the afterReceivePostProcessors property.
The post processor(s) are called after a message is received and before the listener is called.

Spring boot SSE (Server sent events): how to send response dynamically

I am new to SSE (Server Sent Events) . I found a way to send response using SSE in spring boot. I am able to send response for every 20 seconds. I used below code for the same.
public Flux<UserDto> fetchUserEvent() {
return Flux.interval(Duration.ofSeconds(20)).map(intr -> generateUserEvent()).flatMapIterable(x -> x);
}
generateUserEvent() - verify if new user added in DB. If it found user data, will return the same or will return empty object (new UserDto())
But the problem is , this method being called for every 20 seconds .
But , My requirement is to send the empty response to client every 20 seconds and send the respone whenever new user added to DB.
How can I achieve my goal? Or I am totally wrong conceptually.
You should create an event publisher and listener so you can send an event to the emitter when a new user is registered.
Since you're using spring-boot and probably hibernate you can see example here on how to intercept hibernate events.
Hibernate interceptor or listener with Spring Boot and Spring Data JPA
I would personally not use flux and make a scheduled method in spring to send those empty ping responses to the emitter. example of this can be found here: https://www.roytuts.com/server-sent-events-spring-push-notifications/
More info for spring events in general can be found here:
https://www.baeldung.com/spring-events

Spring WebSockets ActiveMQ convertAndSendToUser

I have a Spring Boot app (Jhipster) that uses STOMP over WebSockets to communicate information from the server to users.
I recently added an ActiveMQ server to handle scaling the app horizontally, with an Amazon auto-scaling group / load-balancer.
I make use the convertAndSendToUser() method, which works on single instances of the app to locate the authenticated users' "individual queue" so only they receive the message.
However, when I launch the app behind the load balancer, I am finding that messages are only being sent to the user if the event is generated on the server that their websocket-proxy connection (to the broker) is established on?
How do I ensure the message goes through ActiveMQ to whichever instance of the app that the user is actually "connected too" regardless of which instance receives, say an HTTP Request that executes the convertAndSendToUser() event?
For reference here is my StompBrokerRelayMessageHandler:
#Bean
public AbstractBrokerMessageHandler stompBrokerRelayMessageHandler() {
StompBrokerRelayMessageHandler handler = (StompBrokerRelayMessageHandler) super.stompBrokerRelayMessageHandler();
handler.setTcpClient(new Reactor2TcpClient<>(
new StompTcpFactory(orgProperties.getAws().getAmazonMq().getStompRelayHost(),
orgProperties.getAws().getAmazonMq().getStompRelayPort(), orgProperties.getAws().getAmazonMq
().getSsl())
));
return handler;
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableStompBrokerRelay("/queue", "/topic")
.setSystemLogin(orgProperties.getAws().getAmazonMq().getStompRelayHostUser())
.setSystemPasscode(orgProperties.getAws().getAmazonMq().getStompRelayHostPass())
.setClientLogin(orgProperties.getAws().getAmazonMq().getStompRelayHostUser())
.setClientPasscode(orgProperties.getAws().getAmazonMq().getStompRelayHostPass());
config.setApplicationDestinationPrefixes("/app");
}
I have found the name corresponding to the queue that is generated on ActiveMQ by examining the headers in the SessionSubscribeEvent, that is generated in the listener when a user subscribes to a user-queue, as simpSessionId.
#Override
#EventListener({SessionSubscribeEvent.class})
public void onSessionSubscribeEvent(SessionSubscribeEvent event) {
log.debug("Session Subscribe Event:" +
"{}", event.getMessage().getHeaders().toString());
}
Corresponding queues' can be found in ActiveMQ, in the format: {simpDestination}-user{simpSessionId}
Could I save the sessionId in a key-value pair and just push messages onto that topic channel?
I also found some possibilities of setting ActiveMQ specific STOMP properties in the CONNECT/SUBSCRIBE frame to create durable subscribers if I set these properties will Spring than understand the routing?
client-id & subcriptionName
Modifying the MessageBrokerReigstry config resolved the issue:
config.enableStompBrokerRelay("/queue", "/topic")
.setUserDestinationBroadcast("/topic/registry.broadcast")
Based on this paragraph in the documentation section 4.4.13:
In a multi-application server scenario a user destination may remain
unresolved because the user is connected to a different server. In
such cases you can configure a destination to broadcast unresolved
messages to so that other servers have a chance to try. This can be
done through the userDestinationBroadcast property of the
MessageBrokerRegistry in Java config and the
user-destination-broadcast attribute of the message-broker element in
XML
I did not see any documentation on "why" /topic/registry.broadcast was the correct "topic" destination, but I am finding various iterations of it:
websocket sessions sample doesn't cluster.. spring-session-1.2.2
What is MultiServerUserRegistry in spring websocket?
Spring websocket - sendToUser from a cluster does not work from backup server

how to prevent message re-queue within rabbitmq server?

I'm using direct exchange to publish messages to certain queues with routing keys, all configured in rabbit-server not code, I'm consuming messages with spring micro-service then some failures happens within the receiving method, then the message re-queued causing loop, so I'd like to add a policy with rabbit-server to prevent that kind of re-queuing, could it be added as an argument while binding queue with exchange with specific routing key, or it should be a policy ?
On any exception by default spring send nack with requeue "true". If in your spring consumer application you want to send requeue false, then throw the exception "AmqpRejectAndDontRequeueException". So your consumer code should loook something like this :
`void onMessage(){
try{
// Your Code Here
} catch(Exception e){
throw new AmqpRejectAndDontRequeueException();
}
}`

How to stop consumers

I made a simple Jms project with 2 java files names are MessageSender.java,MessageConsumer.java.one for sending messages to Activemq:Queue and another for consuming messages from Activemq:Queue.Deployed this project in Apache Tomcat.following code was consumer code.
ActiveMQConnectionFactory connectionFactory=new ActiveMQConnectionFactory("admin","admin","tcp://localhost:61617?jms.prefetchPolicy.queuePrefetch=1");
Connection connection=connectionFactory.createConnection();
final Session session=connection.createSession(true, Session.CLIENT_ACKNOWLEDGE);
Queue queue=session.createQueue("ThermalMap");
javax.jms.MessageConsumer consumer=session.createConsumer(queue);
//anonymous class
MessageListener listener = new MessageListener() {
#Override
public void onMessage(Message msg) {
// My business code
}
};
Later If I want to change consumer code,I don't want to stop Tomcatbecause If I stop Tomcat entire jms project should not work. So clients can't able to sent messages to Activemq:Queue.So I don't want to follow this way.
I am thinking, If I stop consumers through Activemq console page.I don't need to stop Tomcat So clients can able to send messages normally.For this I check AMQ console page,I didn't seen any consumers.
Is it correct way to do this.
If it is correct way, How can I do this.
can anyone suggest me.
Thanks.
Call the .close() method on your MessageConsumer.

Resources