Masstransit one fault consumer for all fault message - masstransit

How to have one generic consumer that handle all Fault Messages ?
Do I need to register Fault Consumer for each of my fault messages?

Why not consume Fault?
public class WantAllFaultsGimmeThem : IConsumer<Fault>
{
public async Task Consume(ConsumeContext<Fault> context)
{
// whatever you want to do here
}
}
The only issue is that the Message is not part of this interface and therefore it will not be even deserialised. so you will not have access to the message, only to the message id.

Related

RabbitMQ - How multiple consumers can consume same message from single queue?

Most of the RabbitMQ documentation seems to be focused on round-robin, ie where a single message is consumed by a single consumer. I have a requirement wherein would like to receive the same message from a single queue to multiple subscribed consumers.
Below is my sample consumers code. Here there are 2 listeners listening to the same Queue, but the message is getting received by only one of the consumer. How do I configure it so that the same message gets delivered to both the Consumers? (Consumer1 and Consumer2).
Any help will be highly appreciated.
#Component
public class Consumer1 {
#RabbitListener(queues="test.queue.jsa")
public void recievedMessage(Employee msg) {
System.out.println("Recieved Message: " + msg);
}
}
#Component
public class Consumer2 {
#RabbitListener(queues="test.queue.jsa")
public void recievedMessage(Employee msg) {
System.out.println("Consumed Message: " + msg);
}
}
This is not possible; it just doesn't work that way. Each consumer needs its own queue; use a fanout exchange.

How to subscribe to STOMP messages from an application itself

Is there any way how to subscribe from a topic and forward messaged to another layer of an application (have a new Listener for given topic) using Spring?
Consider following message handler it handler which sends messages to a topic topic/chat/{conversationId}
public class ConversationController{
#MessageMapping("/chat/{conversationId}")
#SendTo("/topic/chat/{conversationId}")
public ConversationMessage createMesage(
#Payload CreateMessage message,
#DestinationVariable String conversationId) {
log.info("handleMessage {}", message);
return conversationService.create( message );
}
}
I would like to listen on this topic and do an action on some messages.
public class Bot{
#SubscribeMapping("/topic/chat/{conversationId}")
public void subscribeUserMessages(
#Payload ConversationMessage message,
#DestinationVariable String conversationId){
// doesn't work
}
}
I've also tried use SimpMessagingTemplate.convertAndSend(..) but it doesn't work neither. Maybe I am doing something wrong.
My application doesn't use full flagged message broker, just the default one in memory broker.

how to send and receive from the same topic within spring cloud stream and kafka

I have a spring-cloud-stream application with kafka binding. I would like to send and receive a message from the same topic from within the same executable(jar). I have my channel definitions such as below:-
public interface ChannelDefinition {
#Input("forum")
public SubscriableChannel readMessage();
#Output("forum")
public MessageChannel postMessage();
}
I use #StreamListener to receive messages. I get all sorts of unexpected errors. At times, i receive
No dispatcher found for unknown.message.channel for every other message
If i attach a command line kafka subscriber to the above forum topic, it recieves every other message.
My application receives every other message, which is exclusive set of messages from command line subscriber. I have made sure that my application subscribes under a specific group name.
Is there a working example of the above usecase?
This is a wrong way to define bindable channels (because of the use of the forum name for both). We should be more thorough and fail fast on it, but you're binding both the input and the output to the same channel and creating a competing consumer within your application. That also explains your other issue with alternate messages.
What you should do is:
public interface ChannelDefinition {
#Input
public MessageChannel readMessage();
#Output
public MessageChannel postMessage();
}
And then use application properties to bind your channels to the same queue:
spring.cloud.stream.bindings.readMessage.destination=forum
spring.cloud.stream.bindings.postMessage.destination=forum
Along with the answer above by Marius Bogoevici, here's an example of how to listen to that Input.
#StreamListener
public void handleNewOrder(#Input("input") SubscribableChannel input) {
logger.info("Subscribing...");
input.subscribe((message) -> {
logger.info("Received new message: {}", message);
});
}
For me, consuming from "input" didn't work. I needed to use method name on #Streamlistener and needed to use #EnableBinding, like below:
#Slf4j
#RequiredArgsConstructor
#EnableBinding(value = Channels.class)
public class Consumer {
#StreamListener("readMessage")
public void retrieve(Something req) {
log.info("Received {{}}", req);
}
}

MessageConsumer.receive() vs MessageConsumer.setMessageListener(new ClassName());

I know the small part that setMessageListener is used when we implements MessageListener on the class.
This below class is for reciever. Both subscribe and publish method are in same class. When i try to execute this my application won't recieve message. It is not producing message also probably because of some error in subscribe method , i am not sure.
public void subscribe(Connection topicConnection, Topic topic) throws JMSException{
TopicSession subscribeSession= (TopicSession) topicConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
topic=subscribeSession.createTopic("topic/mohit");
TopicSubscriber topicSubscriber=subscribeSession.createSubscriber(topic);
topicConnection.start();
Message message=topicSubscriber.receive();
TextMessage textmessage=(TextMessage) message;
System.out.println(textmessage.getText());
}
}
But when i have below code with class extending from MessageListener interface and instead of Message message=topicSubscriber.receive(); i use topicSubscriber.setMessageListener(new Chat()); the application runs fine.Please tell me what is wrong in first implementation.
public void subscribe(Connection topicConnection, Topic topic) throws JMSException{
TopicSession subscribeSession= (TopicSession) topicConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
topic=subscribeSession.createTopic("topic/mohit");
TopicSubscriber topicSubscriber=subscribeSession.createSubscriber(topic);
topicSubscriber.setMessageListener(new Chat());
}
#Override
public void onMessage(Message message) {
try {
System.out.println(((TextMessage) message).getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Both receive() method and a MessageListener are both used for receiving messages.
1) The receive() method is a blocking call meaning the method will not return until a message is received or connection is closed.
2) The MessageListener is the callback way of receiving messages. Application attaches the MessageListener to a consumer/subscriber object instance. The JMS implementation calls back the onMessage method of MessageListener whenever there is a message to be delivered to application. In simple terms the MessageListener.onMessage method is invoked from a different thread and hence it does not block the application thread like the receive method.
Possible reasons on why the receive() method is not getting any publications
1) There were no publications to receive. Hence receive method is waiting.
2) You have not shown the whole code, So I making a guess: You are receiving and publishing from the same thread. Since receive call is blocked, publish code which is after receive() is never executed.

Stomp over websocket using Spring and sockJS message lost

On the client side javascript I have
stomp.subscribe("/topic/path", function (message) {
console.info("message received");
});
And on the server side
public class Controller {
private final MessageSendingOperations<String> messagingTemplate;
ï¼ Autowired
public Controller(MessageSendingOperations<String> messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
#SubscribeMapping("/topic/path")
public void subscribe() {
LOGGER.info("before send");
messagingTemplate.convertAndSend(/topic/path, "msg");
}
}
From this setup, I am occasionally (around once in 30 page refreshes) experiencing message dropping, which means I can see neither "message received" msg on the client side nor the websocket traffic from Chrome debugging tool.
"before send" is always logged on the server side.
This looks like that the MessageSendingOperations is not ready when I call it in the subscribe() method. (if I put Thread.sleep(50); before calling messagingTemplate.convertAndSend the problem would disappear (or much less likely to be reproduced))
I wonder if anyone experienced the same before and if there is an event that can tell me MessageSendingOperations is ready or not.
The issue you are facing is laying in the nature of clientInboundChannel which is ExecutorSubscribableChannel by default.
It has 3 subscribers:
0 = {SimpleBrokerMessageHandler#5276} "SimpleBroker[DefaultSubscriptionRegistry[cache[0 destination(s)], registry[0 sessions]]]"
1 = {UserDestinationMessageHandler#5277} "UserDestinationMessageHandler[DefaultUserDestinationResolver[prefix=/user/]]"
2 = {SimpAnnotationMethodMessageHandler#5278} "SimpAnnotationMethodMessageHandler[prefixes=[/app/]]"
which are invoked within taskExecutor, hence asynchronously.
The first one here (SimpleBrokerMessageHandler (or StompBrokerRelayMessageHandler) if you use broker-relay) is responsible to register subscription for the topic.
Your messagingTemplate.convertAndSend(/topic/path, "msg") operation may be performed before the subscription registration for that WebSocket session, because they are performed in the separate threads. Hence the Broker handler doesn't know you to send the message to the session.
The #SubscribeMapping can be configured on method with return, where the result of this method will be sent as a reply to that subscription function on the client.
HTH
Here is my solution. It is along the same lines. Added a ExecutorChannelInterceptor and published a custom SubscriptionSubscribedEvent. The key is to publish the event after the message has been handled by AbstractBrokerMessageHandler which means the subscription has been registered with the broker.
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ExecutorChannelInterceptorAdapter() {
#Override
public void afterMessageHandled(Message<?> message, MessageChannel channel, MessageHandler handler, Exception ex) {
SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.wrap(message);
if (accessor.getMessageType() == SimpMessageType.SUBSCRIBE && handler instanceof AbstractBrokerMessageHandler) {
/*
* Publish a new session subscribed event AFTER the client
* has been subscribed to the broker. Before spring was
* publishing the event after receiving the message but not
* necessarily after the subscription occurred. There was a
* race condition because the subscription was being done on
* a separate thread.
*/
applicationEventPublisher.publishEvent(new SessionSubscribedEvent(this, message));
}
}
});
}
A little late but I thought I'd add my solution. I was having the same problem with the subscription not being registered before I was sending data through the messaging template. This issue happened rarely and unpredictable because of the race with the DefaultSubscriptionRegistry.
Unfortunately, I could not just use the return method of the #SubscriptionMapping because we were using a custom object mapper that changed dynamically based on the type of user (attribute filtering essentially).
I searched through the Spring code and found SubscriptionMethodReturnValueHandler was responsible for sending the return value of subscription mappings and had a different messagingTemplate than the autowired SimpMessagingTemplate of my async controller!!
So the solution was autowiring MessageChannel clientOutboundChannel into my async controller and using that to create a SimpMessagingTemplate. (You can't directly wire it in because you'll just get the template going to the broker).
In subscription methods, I then used the direct template while in other methods I used the template that went to the broker.

Resources