Reputation: 2950
I'm trying to use a Camel poll-once route that will use a file if it's present and log an error if not.
By default the route does nothing if the file does not exist so I've started by adding consumer.sendEmptyMessageWhenIdle=true
to the URI. I then check for null body to decide whether to log an exception or continue:
from(theFileUri)
.onCompletion()
.onCompleteOnly()
.log("SUCCESS")
.bean(theOtherAction, "start")
.end()
.onException(Exception.class)
.logStackTrace(true)
.log(ERROR, "Failed to load file")
.handled(true)
.end()
.choice()
.when(body().isNotNull())
.to(NEXT_ROUTE_URI)
.endChoice()
.otherwise()
.throwException(new FileNotFoundException(theFileUri))
.endChoice();
There are two problems with this:
If there is a better way to do this then I'd welcome suggestions but I'd also like to know what I'm doing wrong in this method.
Upvotes: 1
Views: 1407
Reputation: 2950
It's still not completely clear to me what is going on. However, I believe that the onException
call needs to be separated from the chain. It looks to me that logStackTrace
applies only to redelivery attempts. The number of attempts defaults to 0 and this is what I want. The only way to access the exception from the Java DSL appears to be a custom Processor
. The getException()
method will return null
if you are using handled(true)
so you must use Exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class)
.
I also suspect that the log message from the onCompletion is due to it running in parallel before the exception aborts:
Camel 2.13 or older - On completion runs in separate thread Icon The onCompletion runs in a separate thread in parallel with the original route. It is therefore not intended to influence the outcome of the original route. The idea for on completion is to spin off a new thread to eg send logs to a central log database, send an email, send alterts to a monitoring system, store a copy of the result message etc. Therefore if you want to do some work that influence the original route, then do not use onCompletion for that. Notice: if you use the UnitOfWork API as mentioned in the top of this page, then you can register a Synchronization callback on the Exchange which is executed in the original route. That way allows you to do some custom code when the route is completed; this is how custom components can enlist on completion services which they need, eg the File component does that for work that moves/deletes the original file etc.
Since I want to not run this code on exception, I think I can just abort the route with the exception.
I currently have this:
onException(Exception.class)
.handled(true)
.process(new Processor()
{
@Override
public void process(Exchange anExchange) throws Exception
{
Exception myException = anExchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
LOGGER.error("Failed to load", myException);
}
});
from(theFileUri)
.choice()
.when(body().isNotNull())
.to(NEXT_ROUTE_URI)
.log("SUCCESS")
.bean(theOtherAction, "start")
.endChoice()
.otherwise()
.throwException(new FileNotFoundException(theFileUri));
Upvotes: 1