Include Mule Error in custom object, then redirect to O/JMS endpoint - jms

We have implemented a global exception strategy as part of our Mule flow which redirects the payload object to a JMS outbound endpoint - the endpoint receives the object as a payload but we would also like to include exception information in the payload object itself so that the receiving thread can consume it. So for example the following block works fine but how do I intercept the exception and update the payload with exception summary and stack information?
catch-exception-strategy name="globalCatchStrategy"
set-payload value="Error : #[exception.summaryMessage]"/
jms:outbound-endpoint connector-ref="ActiveMQ" doc:name="JMS" queue="${jms.outbound.queue}"
catch-exception-strategy
NOTE - I had to remove the open and close XML braces for it to render in stackoverflow.

Ok, I managed to resolve this issue in the following manner - we send a serializable DTO as a payload in the JMS message which gets returned back if there is an exception within the flow - so I added the exception attributes to the payload object and attached a transformer before the JMS outbound endpoint above - so now the flow looks like this
catch-exception-strategy name="globalCatchStrategy"
custom-transformer class="MyTransformerClass" doc:name="Exception Extractor"
jms:outbound-endpoint connector-ref="ActiveMQ" doc:name="JMS" queue="${jms.outbound.queue}"
catch-exception-strategy
And in the MyTransformerClass instance get the payload as such
ExceptionPayload exceptionPayload = message.getExceptionPayload();

Related

E 02/07/19-07:51:49.358 [-5] JMSListener exception : java.lang.ClassCastException: com.ibm.jms.JMSMessage cannot be cast to javax.jms.TextMessage

E 02/07/19-07:51:49.358 [-5] JMSListener exception : java.lang.ClassCastException: com.ibm.jms.JMSMessage cannot be cast to javax.jms.TextMessage
This is a ticky one. We put an xml message onto a queue and our code consumed it no problem. The next day, we put another xml message onto the same queue, and the same code threw this error.
I'm looking for suggestions on how to get more info out of what's actually happening, or if anyone else has had intermittent class cast exceptions like this with JMS.
Please note that not all 'XML' messages are sent as JMS TextMessage. I've come across the same thing. Some applications will decide to send you the XML content as JMS BytesMessage (and put the text inside the byte array body). So make sure your sending is really sending you a TextMessage.
One way to see this is to stop your consumer and look at the queued messages with MQExplorer: the Named Property mcd.Msd should show jms_text if it was sent as proper MQ JMS TextMessage. If the data is received from a non-JMS application, the MQ format matters. If the format is MQFMT_STRING, the message is received as a JMS TextMessage. Otherwise, it is received as a JMS BytesMessage !
So either change your publisher to set the value of format to be MQFMT_STRING or change your consumer application to remove the cast to TextMessage and instead also accept BytesMessages and construct the text from the body's byte array.

MassTransit fault consumer not invoked for request/response

What is the best practice for handling exceptions in MassTransit 3+ with regard to Request/Response pattern? The docs here mention that if a ResponseAddress exists on a message, the Fault message will be sent to that address, but how does one consumer/receive the messages at that address? The ResponseAddress for Bus.Request seems to be an auto-generated MassTransit address that I don't have control over, so I don't know how to access the exception thrown in the main consumer. What am I missing? Here's my code to register the consumer and its fault consumer using Unity container:
cfg.ReceiveEndpoint(host, "request_response_queue", e =>
{
e.Consumer<IConsumer<IRequestResponse>>(container);
e.Consumer(() => container.Resolve<IMessageFaultConsumer<IRequestResponse>>() as IConsumer<Fault<IRequestResponse>>);
});
And here's my attempt at a global message fault consumer:
public interface IMessageFaultConsumer<TMessage>
{
}
public class MessageFaultConsumer<TMessage> : IConsumer<Fault<TMessage>>, IMessageFaultConsumer<TMessage>
{
public Task Consume(ConsumeContext<Fault<TMessage>> context)
{
Console.WriteLine("MessageFaultConsumer");
return Task.FromResult(0);
}
}
This approach DOES work when I use Bus.Publish as opposed to Bus.Request. I also looked into creating an IConsumeObserver and putting my global exception logging code into the ConsumeFault method, but that has the downside of being invoked every exception prior to the re-tries giving up. What is the proper way to handle exceptions for request/response?
First of all, the request/response support in MassTransit is meant to be used with the .Request() method, or the request client (MessageRequestClient or PublishRequestClient). With these methods, if the consumer of the request message throws an exception, that exception is packaged into the Fault<T>, which is sent to the ResponseAddress. Since the .Request() method, and the request client are both asynchronous, using await will throw an exception with the exception data from the fault included. That's how it is designed, await the request and it will either complete, timeout, or fault (throw an exception upon await).
If you are trying to put in some global "exception handler" code for logging purposes, you really should log those at the service boundary, and an observer is the best way to handle it. This way, you can just implement the ConsumeFault method, and log to your event sink. However, this is synchronous within the consumer pipeline, so recognize the delay that could be introduced.
The other option is to of course just consume Fault<T>, but as you mentioned, it does not get published when the request client is used with the response address in the header. In this case, perhaps your requester should publish an event indicating that operation X faulted, and you can log that -- at the business context level versus the service level.
There are many options here, it's just choosing the one that fits your use case best.

How does Spring WebSocket send message to a specific user?

I am reading the book Spring in Action 4 to work with STOMP messaging over WebSocket.
Suppose the user destination prefix is set as "/user" as below:
registry.setUserDestinationPrefix("/user");
Then client subscribes to a destination with below JavaScript code:
stomp.subscribe("/user/queue/notifications", handleNotifications);
Then on the server, the actual destination that the client subscribes to should be derived from its session, maybe like this:
/queue/notifications-user6hr83v6t --- (1)
Then I use the SimpMessagingTemplate to send message to that user:
messaging.convertAndSendToUser( username, "/queue/notifications",
new Notification("You just got mentioned!"));
Then the message will be sent to destination like this:
/user/<username>/queue/notifications ---(2)
Well, the two destinations (1) and (2) look different, how could the message ever reach the client?
The path
/user/<username>/queue/notifications
seems to be the "logical" path which is used in documentation. It is also initially created with convertAndSendToUser method. It is then translated into a technical format which is done in UserDestinationMessageHandler class in this line
UserDestinationResult result = this.destinationResolver.resolveDestination(message);
eg.
Given the subscription:
stompClient.subscribe('/user/queue/reply', function (greeting) { ...
sending a message with
stompClient.send("/app/personal", ...
and intercepting it with
#MessageMapping("/personal")
public void personalMessage(SimpMessageHeaderAccessor headerAccessor, PoCRequestMessage message) {
SimpMessageHeaderAccessor ha = SimpMessageHeaderAccessor
.create(SimpMessageType.MESSAGE);
ha.setSessionId(headerAccessor.getSessionId());
ha.setLeaveMutable(true);
PoCReplyMessage reply = new PoCReplyMessage("Personal Message" + message.getName());
simpMessagingTemplate.convertAndSendToUser(headerAccessor.getSessionId(), "/queue/reply", reply, ha.getMessageHeaders());
}
the destination will be resolved as follows:
source destination: /user/zojdn53y/queue/reply
target destination: /queue/reply-userzojdn53y
this is how the final destination name is resolved.
The target destination is the real name of the queue that is created (at least as long an external message broker is used - didn't check this for a simple in-memory broker but I assume this would be the same).
One important thing to note is that when you want to use an unauthenticated user (most often scenario when experimenting with Websockets) you need to additionally put the message headers in convertAndSendToUser method - this is well described in
Spring WebSocket #SendToSession: send message to specific session

Spring Integration error channel solution

Hello I'm very very new to Spring Integration.
I have known that error channel throws exception parameter to the channel.
but when program are working in error handling I need to get the current state before exception occur(eg. an object that setting some value in main process or string)
the question is how can I sent other parameter(eg. an object) come with exception to error channel?
or I have to use other solution?
thank you,
well, you get something like (Message < MessageHandlingException > msg ) as parameter in error handler method. Then using
msg.getPayload().getFailedMessage()
you gain access to message which failed. If its not enough then you can set your object as header with < header-enricher > somewhere before possible exception and fetch it in you error handler:
msg.getPayload().getFailedMessage().getHeaders().get("trackedImage");

Throwing exception from ServiceActivator vs. Filter behaves differently

In our application we have error handling mechanism, where we throw runtime exceptions on an error. I noticed a strange behavior and I want to understand the mechanism underlying this one
1) Situation 1: Exception thrown from ServiceActivator is converted to MessageHandlingException
When an error occurs in a ServiceActivator, we throw an exception. The message we get on ErrorChannel has PayLoad as org.springframework.integration.MessageHandlingException and actual exception thrown as cause
2) Situation 2: Exception thrown from Filter is not masked with MessageHandlingException
When an error occurs in Filter, and we throw exception, then PayLoad is actual exception, and is not masked with org.springframework.integration.MessageHandlingException
I have a few questions:
Why exception throwing from ServiceActivator behaves differently than in Filter
Are there some "best practices" around error handling in Spring-integration projects, while utilizing the errorChannel and related infrastructure
Update 1:
Filter extends AbstractFileListFilter which is part of a filter chain- a custom CompositeFileFilter which implements FileListFilter
CompositeFileFilter is being used by a file:inbound-channel-adapter and which passes the output to a Channel declared below:
<int:channel
id="channelForFilesComingIn"
datatype="java.io.File"
>
<int:dispatcher task-executor="dispatchExecutor" />
</int:channel>
Update 2:
Whet we are trying to do is read files from filesystem and process them. In file reading part, using file:inbound-channel-adapter with a CompositeFilter which filters files which are not completely uploaded or don't meet naming standards.
After all filters pass, file is handed over to a ServiceActivator for processing
In any of above (Filter chain or Service) , if there is an error condition, it has to be reported to DB and by email. For achieving this we are throwing ApplicationException which are caught by errorChannel, and passed to specialized channels.
Just to make it clear, a MessageHandlingException is thrown (wraps user exception) when a Message HANDLER fails - a message handler is something that HANDLES a message.
If an exception is thrown in the MessageSource, there is no message yet so a MessageHandlingException (or any MessagingException) does not apply.
Instead, the poll fails and the exception is thrown back to the poller.
If you want to handle exceptions in a polled endpoint (MessageSource), you need to give the poller an ErrorHandlingTaskExecutor, to which you can provide an ErrorHandler and do what you want with the exception, but since there is no message yet, it is the original exception thrown by the MessageSource.
If you want to send it to the error channel, you'll need to do that in your custom ErrorHandler.

Resources