Spring Integration error channel solution - spring

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");

Related

How to record each throwable when using .onFailure().retry() with delay between retries

I need to record failure reason in metrics for each failed http call when using Vert.x WebClient. This compiles:
.onFailure()
.retry()
.withBackOff(Duration.ofMillis(INITIAL_RETRY_DELAY_MS))
.until(retryTimeExpired(wrapper))
I'm recording metrics in retryTimeExpired method. But at runtime I get this:
Caused by: java.lang.IllegalArgumentException: Invalid retry configuration, `when` cannot be used with a back-off configuration
at io.smallrye.mutiny.groups.UniRetry.when(UniRetry.java:156)
at io.smallrye.mutiny.groups.UniRetry.until(UniRetry.java:137)
I could of course add sleep but this is reactive. It would be possible to block for a short time but I would hate to block the thread. Any ideas how to do this without sleep?
You could try using many sequential onFailures. As long as the first doesn't handle the exception (recoverWithItem, recoverWithNull, recoverWithUni) or throw its own the next should observe the same failure.
service.apiMethod(key)
.invoke(record -> logger.info("Succeeded to read record."))
.onFailure()
.invoke(exception -> logger.warn("Failed to read record."))
.onFailure()
.retry().withBackOff(delay).indefinitely();

Receivetask in camunda is not working as expected

We have been using camunda 7.4 version in most of our projects along with camunda-bpm-spring-boot-starter 1.1.0.
We have a project where in the camunda flow we try to publish a message to a message broker which internally is consumed by another system and re-publish a new message to the same message broker. Then we trigger a receiveTask to receive that message and process further. To listen to the incoming message we use org.springframework.amqp.core.MessageListener and we define the message co-relation for receiveTask within the onMessage() method. But we get below error in doing so
org.camunda.bpm.engine.MismatchingMessageCorrelationException: Cannot correlate message 'ReceiveAmsharedResponse': No process definition or execution matches the parameters
We are trying to figure where the problem is? Is it in the version of camunda we are using or the problem is with the usage of receiveTask. We tried all approaches defined in https://docs.camunda.org/manual/7.4/reference/bpmn20/tasks/receive-task/ but no luck.
For the method createMessageCorrelation we get above error. And for other methods we get a NPE as EventSubscription/Execution objects are null.
Sample Camunda flow receiveTask Usage is as below:
<bpmn2:receiveTask id="ReceiveTask" name="Receive Task" messageRef="Message_06nl07f">
<bpmn2:incoming>SequenceFlow_xyz</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_190m9nx</bpmn2:outgoing>
</bpmn2:receiveTask>
......
......
<bpmn2:message id="Message_06nl07f" name="Message" />
And sample message co-relation code:
class XYZ implements MessageListener {
onMessage() {
runtimeService.createMessageCorrelation("Message")
.processInstanceBusinessKey(resourceId)
.setVariable(ACTIVITY_RESULT, activityResult)
.correlate();
}
Any help would be appreciated?
Thanks,
Viswanath
Assuming your process looks something like this:
O -- ( M ) -- ( M ) -- O
send receive
If the response message is send very fast, it possible that the onMessage and message correlation is executed before the message event subscription is persisted in the database. Basically the message arrives while the send task is stil being executed.
One way to avoid this would be to create the message subscription in parallel with sending the event:
O -- + -- ( M ) -- + -- O
| send |
`----( M ) --´
receive
Regarding to the given exception message which is :
org.camunda.bpm.engine.MismatchingMessageCorrelationException: Cannot correlate message 'ReceiveAmsharedResponse': No process definition or execution matches the parameters
I assume that you correlate a message with the name ReceiveAmsharedResponse, but you defined a Message with a different name for your ReceiveTask.
Changing the definition of your Message to the following should work:
<bpmn2:message id="Message_06nl07f" name="ReceiveAmsharedResponse" />
Assuming your process looks something like this:
O -- ( M ) -- ( M ) -- O
send receive
This error means that a response was received "earlier" than the request was sent.
And by sent, I mean the whole transaction of the send-request process.
So, in other words, because of the fast response, there is no commited transaction in Camunda Database for the send-request process. Thus, when camunda processes the response-received process, it is not possible to correlate the response-received with the send-request.
One suggested solution is to use Async Continuations that Camunda offers and you might check in their official website. More specifically, you might use Async Before at the send-request level:
( M )
send
Async Before will save the transaction in Camunda database, before the send-request process will begin. Τherefore, it will be possible for the response to be correlated.

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

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();

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.

Sending JMS message over corrupted network

I am performing some simple tests with ActiveMQ to see how it performs on a non stable network. The first test consists in a producer that sends messages to a remote queue. The message is of type ObjectMessage with serializable content inside (a list of Objects).
With a good network everything works correctly, but when I launch the same tests using netem to simulate packages losses, delays and corruptions I get the following error when consuming the messages when trying to extract the content of the Message:
2011-03-16 11:59:21,791 ERROR [com.my.MessageConsumer] Failed to build body from bytes. Reason: java.io.StreamCorruptedException: invalid handle value: 017E0007
javax.jms.JMSException: Failed to build body from bytes. Reason: java.io.StreamCorruptedException: invalid handle value: 017E0007
So it seems like the message was corrupted while sending to the remote Queue but anyway stored, and only when is consumed the consumer see that the message is corrupted.
After this I will use a local Queue and a Network Connector to forward the messages to the remote Queue, and that I hope it solve the problem, but I was surprised that there was not any kind of validation between the producer and the destination (at least a checksum or something like that) that guarantees a correct delivery, am I doing something wrong or is the normal behaviour?
I don't have the code here right now, but it was super simple, just a MessageListener:
public class myMessageConsumer implements MessageListener{
public void onMessage(Message message){
try
{
if (message instanceof ObjectMessage){
ObjectMessage myMessage = (ObjectMessage) message;
List dtoList = (List) myMessage.getObject();
}
} catch(Exception ex){
ex.printStackTrace();
}
}
}
If the exact code is needed I'll put it when I go back from holidays, but it was exactly like that.
The broker isn't going to validate the contents of each and every message that it processes, that would be a tremendous waste of time and slow down message dispatch significantly. The client received a bad message and threw a JMSException to indicate that the message contents were corrupted which should be sufficient for your app to respond correctly.
Where's your code?
If that exception comes from your code, seems like it's possible that you've got a bug. For example, getting some JMS error receiving the message but messing up error handling and trying to process the results anyway. For a test like you describe, you'd need a good focus on error handling in your clients.
I don't have experience w/ ActiveMQ, but it seems very surprising that it'd allow corrupt message delivery. Not that I'm wanting the JMS implementation to unpack the ObjectMessage to check. Just that it should deliver a byte-for-byte uncorrupted copy of what was sent. Or error out if it can't.

Resources