Unexpected behavior of LoggingErrorHandler in Camel - java

So, I have a camel context that has a DeadLetterChannel with no redeliveries at the context level. Within the context I have a route:
from("direct:input")
.routeId("enrichHeader")
.setHeader("myHeader").constant("someValue)
.to("direct:output");
I have a unit test in which I interceptSendToEndpoint("direct:output") and cause an exception to be thrown.
Then in the unit test I do producerTemplate.sendBody(theBody).
Now, as configured above on exception the message gets sent to the dead letter channel. All's well. However, if I configure a loggingErrorHandler I get odd behavior. So if I update the above route as follows:
from("direct:input")
.routeId("enrichHeader")
.errorHandler(
loggingErrorHandler("com.myco.myproject")
.level(LoggingLevel.WARN))
.setHeader("myHeader").constant("someValue)
.to("direct:output");
When I run the test now I get two unexpected behaviors. First, the exception is still logged at level ERROR instead of the configured WARN. Second, the exception is propagated back to the producerTemplate.sendBody(theBody) invokation.
On the one hand, the logging at ERROR is obviously odd. The other part that seems odd is that the handler is propagating the exception. I would have thought it would have marked it as handled and be done with it.
Is this expected behavior? Seems like documentation for the LoggingErrorHandler is lacking.

LoggingErrorHandler do nothing more than logging the exception.
if you want to skip the exception you have to define a policy as followed
onException(com.myco.myproject.MyException.class).continued(true);
or you have to use a doTry()..doCatch() just like try{...} catch{...} block in java.
for example:
from("direct:input").routeId("enrichHeader")
.doTry()
.setHeader("myHeader").constant("someValue)
.to("direct:output")
.doCatch(MyException.class)
.process(new MYExceptionLoggerAndHandler())
.end();

Related

Axon framework: Handling database exceptions in state-stored aggregates

I am new to Axon framework and am trying to implement an application using CQRS with state-stored aggregates. The application relies on a database constraint (using H2 for now) to enforce uniqueness on a name attribute. I would like to catch this exception and rethrow it as a user-friendly domain exception.
Per the Axon documentation:
Exception Handling says "an #ExceptionHandler will only handle exceptions thrown from message handling functions in the same class"
Message Intercepting documentation says "A function annotated with #ExceptionHandler will be regarded as a handler interceptor which will only be invoked for exceptional results. Using annotated functions to this end for example allow you to throw a more domain specific exception as a result of a thrown database/service exception."
But I cannot get this to work. I have tried adding exception handlers as follows:
#ExceptionHandler
public void handle(ConstraintViolationException ex) throws Exception {
if (ex.getMessage().contains("UNQ_COMPANY_ID") || ex.getMessage().contains("UNQ_PLAN_NAME")) {
throw new DomainException("Plan name and company id must be unique");
}
throw ex;
}
but this method is not called. I have tried putting the exception handler method on the aggregate and on a separate command handler class, tried adding resultType=ConstraintViolationException.class, and tried catching other types of exceptions including Exception, RuntimeException, AxonServerRemoteCommandHandlingException, etc. but this method is never called.
I can see the error in the log output:
org.axonframework.axonserver.connector.command.AxonServerRemoteCommandHandlingException: An exception was thrown by the remote message handling component: org.hibernate.exception.ConstraintViolationException: could not execute statement
Is it possible to catch database exceptions in state-stored aggregates? If it is, can someone point me towards what I am doing wrong?
The statement "an #ExceptionHandler will only handle exceptions thrown from message handling functions in the same class" makes me wonder whether I need to create a custom repository class (rather than using the default GenericJpaRepository) but that seems like a lot more work than should be necessary.
Thank you!
Update: I was able to roughly accomplish what I want by adding a UnitOfWork parameter to the #CommandHandler method and using it to registering a rollback callback on it as follows:
uow.onRollback(unit -> {
DefaultUnitOfWork duow = (DefaultUnitOfWork) unit;
Throwable ex = duow.getExecutionResult().getExceptionResult();
while (ex != null) {
if (ex.getMessage().contains("UNQ_PLAN_NAME")) {
throw new RuntimeException("Plan name must be unique");
}
ex = ex.getCause();
}
});
But this seems kind of verbose, as well as limiting me to throwing unchecked exceptions only. This also doesn't feel like the right way to do this though because I assume the purpose of the #ExceptionHandler annotation is to eliminate need for code like the above.
This is doable of course.
Actually, the best pointer I could give you if the code-samples repo where you can see a sample about distributed exceptions.
In general, as you could see in your shared log, the 'original' exception is wrapped into an AxonServerRemoteCommandHandlingException meaning you will have to handle that. Doing that, you can pretty much add anything to the details field of this class, adding the indication you had a ConstraintViolationException for example (or an ERROR_CODE, like HTTP protocol does) and you are fine to unwrap it on the other side.
What might be the "gotcha" you require, is to know that an #ExceptionHandler annotated method should reside in the object handling the message. So if you want to react to a failing command handling operation (which would be the case in your sample), you will need to place the exception handler in the Aggregate, next to the Command Handler.
That fact you get an AxonServerRemoteCommandHandlingException to me suggests the exception is caught on the command dispatching end. So, prior to dispatching a command on the CommandGateway/CommandBus.
However, whether this is the problem at hand, isn't clear to me right now, since the sample only shows the exception handler and not where it resides. Please share whether my assumption on the placement of the exception handler is correct. If not, we'll dive into this deeper to get to the cause.

How to close spring integration channel?

I have project with Spring Integration and input/output channels. The problem is in the last piece of config
<int:transformer id="testTransformer" input-channel="inChannel" method="processor"
output-channel="outChannel">
<bean class="someClass"/>
</int:transformer>
It gives me an error
failure occurred in gateway sendAndReceive: No reply produced by handler 'testTransformer', and its 'requiresReply' property is set to true
I understand that it's about my outputChannel is not initialized, so how correctly make program finished?
No reply produced by handler 'testTransformer', and its 'requiresReply' property is set to true
That means that the transformer component is strictly request-reply and it definitely has to return something.
That's no the problem of your configuration, but your logic in the someClass.processor() method. Reconsider it to return anything valuable instead of null.
If null is possible by your logic and you manage it somehow in your flow, consider to switch to the service-activator. This one isn't so strict for its reply and allow to return null. But at the same time you should bear in mind that the flow stops exactly here. The null is invalid for messaging and is an indicator do stop processing because nothing what is payload any more.

catch exception in camel

I have a route in camel which is as follows
errorHandler(deadLetterChannel("file:somelocation");
from("jms:queuwlocation").to(
"file:someLocation");
I have read that camel error handling comes when there's a processing between two nodes, such as Processor, Predicate etc. But what if I cannot consume the message, in my case the camel cannot connect to jms. How should I log this exception ?. As I am trying to use a deadLetterChannel to send the message to filesystem, but since I have not received the message there is nothing new on the file location. how should I encounter this type of situation?
The problem you are facing might be due to the JMS Connection Exception being thrown outside of the life cycle of your Camel exchange. Claus Ibsen refers this in "Camel in Action" as a chicken and egg situation:
You can picture this as a chicken and egg situation. Camel's error handler only applies
during routing of Exchanges (chicken), but the consumer needs successfully to create the
Exchange (hatch the egg). So if we want a chicken but only have an egg, what can we do?
The answer lies with extending the error handling boundaries to cover the entire Camel JMS Consumer:
As
a figure of speech we can tell Camel to treat the eggs as if they were chickens. This is done by
configuring the consumer to bridge its internal error handler with Camel's error handler.
For the JMS module, I suspect this involves playing around with the transferException property. Good luck with that!
Futhermore, I don't think using a deadletter channel is appropriate for your problem, since you don't gain anything from taking messages out of the queue when encountering a connectivity problem.
Typically connectivity problems are self fixing, e.g. a server was restarted, and can be solved by retrial. For your use case, a sensible redelivery strategy can do this. Luckily Camel is really good at this: https://camel.apache.org/redeliverypolicy.html.
I recommend an indefinite redelivery until connectivity commences. Something like this:
onException(SomeJmsTimeoutException.class, SomeJmsConnectivityException.class)
.useOriginalMessage()
.maximumRedeliveries(Integer.MAX_VALUE)
.retryAttemptedLogLevel(LoggingLevel.ERROR)
.logRetryStackTrace(true)
.redeliveryDelay(1000 * 60);
As far as I know the error handling does not come in play just between the nodes. It has a more complete scope than that. It also depends on the type of error you are facing.
How you should log the exception?
Well why don't you do it like this?
DeadLetterChannel defined and you refer to it on your CamelContext.
The deadletteruri refers to another route - call it errorhandler route.
In the errorhandler route you can set headers that contain errors and other information you want to set.
In the errorhandler route in your "to" send the error message to a file writing the headers with it like you would with a log file.

How to handle badly formatted messages on the consumer side when working with Spring Integration and RabbitMQ

I am currently working on a project involves consuming messages from RabbitMQ brocker. However, I am still new to Spring Integration, AMQP and RabbitMQ.
I have an issue with consuming malformed messages formats. When my consumer receives a malformed message it returns it back the queue then RabbitMQ sends it back which creates an endless cycle.
In Spring Integration documentation there are some configuration that can be implemented to that this kind of message are no returned back to the queue.
However I could not understand how to implement that.
What I want is to be able to configure some kind of bean that has a format like
class ExceptionHandler {
public void handle(Throwable e ) {
Logger.log("Some log ... we don't give a Sh** ... ") ;
}
}
I've checked section 3.9 Exception Handling
and 3.15.3 Message Listeners and the Asynchronous Case
but unfortunately I could not understand anything.
So, if you have an example code or a link to one send it I will be greateful.
Yes, that's is one of the correct solution - to throw AmqpRejectAndDontRequeueException, when you decide that the message should not be requeued.
There is also defaultRequeueRejected on the SimpleMessageListenerContainer, which is true by default.
You maybe should to take a look to the DLX/DLQ solution to not lose those malformed messages.
Please, share the StackTrace which bothers you.
There is such a code in the SimpleMessageListenerContainer:
catch (AmqpRejectAndDontRequeueException rejectEx) {
/*
* These will normally be wrapped by an LEFE if thrown by the
* listener, but we will also honor it if thrown by an
* error handler.
*/
}
After a lot of try-fails attempts I was able to handle the error. However I am struggling with harboring the exception log now. I don't understand why this is implemented this way. I was able to handle the log issue too.
It turns that there is another way to say that you don't want to return the message back it is with acknowledge-mode="NONE" attribute. Checkout 10.2 Inbound Channel Adapter section.This way you don't even need to throw that ugly exception.
< bean id="handler" class="MessagesErrorHandler"/>
< int-amqp:inbound-channel-adapter
error-handler="handler"
id="idActivityAdapter"
channel="channelName"
queue-names="activityQueue"
/>
import org.springframework.util.ErrorHandler;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
public class MessagesErrorHandler implements ErrorHandler {
#Override
public void handleError(Throwable throwable) {
System.out.println("YESSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ERROR IS HANDLED !!!!");
throw new AmqpRejectAndDontRequeueException(throwable);// this very important
//so that message don't go back to the queue.
}
}
The AmqpRejectAndDontRequeueException is a signal to the container to reject and not requeue the message; by default, it requeues any exception.
Alternatively, you can manually wire up a SimpleMessageListenerContainer bean; set defaultRequeueRejected to false and add it to the adapter using the container attribute. Then, all exceptions will cause messages to be rejected and not requeued.
Also, instead of an error-handler, you can use an error-channel and throw the AmqpRejectAndDontRequeueException from the error flow.

Restlet: Log Stack Trace for All 500 Errors

I'd like my Restlet application to log the stack trace for any Resource that generates a 500-series HTTP error (using the Context's Logger). As far as I can tell, this is not the default behavior.
In other words, I don't want my Resource classes to have any logger code at all in the represent and acceptRepresentation methods - they just throw a ResourceException. I want the logging logic to be handled in a centralized way across all Resource instances.
I can think of a couple of hackish ways of doing this (e.g., inherit from a Resource subclass that handles the logging logic), but it just seems like this is something that should be built-in to the framework.
What am I missing?
Take a look at StatusService:
Service to handle error statuses. If an exception is thrown within your application or Restlet code, it will be intercepted by this service if it is enabled. When an exception or an error is caught, the getStatus(Throwable, Request, Response) method is first invoked to obtain the status that you want to set on the response. [...]
I just discovered this last month and it allowed me to really compress a lot of my error handling code and also to ensure that exceptions were being handled, and being handled uniformly.
You might be able to use a filter to do this; in afterHandle() it could check the status code, and then try to log the exception. I'm not sure whether the exceptions are available to the filters though.

Categories

Resources