use of org.apache.camel.spi.SubUnitOfWorkCallback in project camel by apache.
the class DefaultUnitOfWork method done.
public void done(Exchange exchange) {
log.trace("UnitOfWork done for ExchangeId: {} with {}", exchange.getExchangeId(), exchange);
boolean failed = exchange.isFailed();
// at first done the synchronizations
UnitOfWorkHelper.doneSynchronizations(exchange, synchronizations, log);
// notify uow callback if in use
try {
SubUnitOfWorkCallback uowCallback = getSubUnitOfWorkCallback();
if (uowCallback != null) {
uowCallback.onDone(exchange);
}
} catch (Throwable e) {
// must catch exceptions to ensure synchronizations is also invoked
log.warn("Exception occurred during savepoint onDone. This exception will be ignored.", e);
}
// unregister from inflight registry, before signalling we are done
if (exchange.getContext() != null) {
exchange.getContext().getInflightRepository().remove(exchange);
}
// then fire event to signal the exchange is done
try {
if (failed) {
EventHelper.notifyExchangeFailed(exchange.getContext(), exchange);
} else {
EventHelper.notifyExchangeDone(exchange.getContext(), exchange);
}
} catch (Throwable e) {
// must catch exceptions to ensure synchronizations is also invoked
log.warn("Exception occurred during event notification. This exception will be ignored.", e);
}
}
use of org.apache.camel.spi.SubUnitOfWorkCallback in project camel by apache.
the class RedeliveryErrorHandler method processAsyncErrorHandler.
/**
* This logic is only executed if we have to retry redelivery asynchronously, which have to be done from the callback.
* <p/>
* And therefore the logic is a bit different than the synchronous <tt>processErrorHandler</tt> method which can use
* a loop based redelivery technique. However this means that these two methods in overall have to be in <b>sync</b>
* in terms of logic.
*/
protected void processAsyncErrorHandler(final Exchange exchange, final AsyncCallback callback, final RedeliveryData data) {
// can we still run
if (!isRunAllowed(data)) {
log.trace("Run not allowed, will reject executing exchange: {}", exchange);
if (exchange.getException() == null) {
exchange.setException(new RejectedExecutionException());
}
callback.done(data.sync);
return;
}
// did previous processing cause an exception?
boolean handle = shouldHandleException(exchange);
if (handle) {
handleException(exchange, data, isDeadLetterChannel());
onExceptionOccurred(exchange, data);
}
// compute if we are exhausted or not
boolean exhausted = isExhausted(exchange, data);
if (exhausted) {
Processor target = null;
boolean deliver = true;
// the unit of work may have an optional callback associated we need to leverage
UnitOfWork uow = exchange.getUnitOfWork();
if (uow != null) {
SubUnitOfWorkCallback uowCallback = uow.getSubUnitOfWorkCallback();
if (uowCallback != null) {
// signal to the callback we are exhausted
uowCallback.onExhausted(exchange);
// do not deliver to the failure processor as its been handled by the callback instead
deliver = false;
}
}
if (deliver) {
// should deliver to failure processor (either from onException or the dead letter channel)
target = data.failureProcessor != null ? data.failureProcessor : data.deadLetterProcessor;
}
// we should always invoke the deliverToFailureProcessor as it prepares, logs and does a fair
// bit of work for exhausted exchanges (its only the target processor which may be null if handled by a savepoint)
boolean isDeadLetterChannel = isDeadLetterChannel() && target == data.deadLetterProcessor;
deliverToFailureProcessor(target, isDeadLetterChannel, exchange, data, callback);
// we are breaking out
return;
}
if (data.redeliveryCounter > 0) {
// we are doing a redelivery then a thread pool must be configured (see the doStart method)
ObjectHelper.notNull(executorService, "Redelivery is enabled but ExecutorService has not been configured.", this);
// let the RedeliverTask be the logic which tries to redeliver the Exchange which we can used a scheduler to
// have it being executed in the future, or immediately
// Note: the data.redeliverFromSync should be kept as is, in case it was enabled previously
// to ensure the callback will continue routing from where we left
AsyncRedeliveryTask task = new AsyncRedeliveryTask(exchange, callback, data);
// calculate the redelivery delay
data.redeliveryDelay = determineRedeliveryDelay(exchange, data.currentRedeliveryPolicy, data.redeliveryDelay, data.redeliveryCounter);
if (data.redeliveryDelay > 0) {
// schedule the redelivery task
if (log.isTraceEnabled()) {
log.trace("Scheduling redelivery task to run in {} millis for exchangeId: {}", data.redeliveryDelay, exchange.getExchangeId());
}
executorService.schedule(task, data.redeliveryDelay, TimeUnit.MILLISECONDS);
} else {
// execute the task immediately
executorService.submit(task);
}
}
}
use of org.apache.camel.spi.SubUnitOfWorkCallback in project camel by apache.
the class RedeliveryErrorHandler method process.
/**
* Process the exchange using redelivery error handling.
*/
public boolean process(final Exchange exchange, final AsyncCallback callback) {
final RedeliveryData data = new RedeliveryData();
// do a defensive copy of the original Exchange, which is needed for redelivery so we can ensure the
// original Exchange is being redelivered, and not a mutated Exchange
data.original = defensiveCopyExchangeIfNeeded(exchange);
// use looping to have redelivery attempts
while (true) {
// can we still run
if (!isRunAllowed(data)) {
log.trace("Run not allowed, will reject executing exchange: {}", exchange);
if (exchange.getException() == null) {
exchange.setException(new RejectedExecutionException());
}
// we cannot process so invoke callback
callback.done(data.sync);
return data.sync;
}
// did previous processing cause an exception?
boolean handle = shouldHandleException(exchange);
if (handle) {
handleException(exchange, data, isDeadLetterChannel());
onExceptionOccurred(exchange, data);
}
// compute if we are exhausted, and whether redelivery is allowed
boolean exhausted = isExhausted(exchange, data);
boolean redeliverAllowed = isRedeliveryAllowed(data);
// if we are exhausted or redelivery is not allowed, then deliver to failure processor (eg such as DLC)
if (!redeliverAllowed || exhausted) {
Processor target = null;
boolean deliver = true;
// the unit of work may have an optional callback associated we need to leverage
SubUnitOfWorkCallback uowCallback = exchange.getUnitOfWork().getSubUnitOfWorkCallback();
if (uowCallback != null) {
// signal to the callback we are exhausted
uowCallback.onExhausted(exchange);
// do not deliver to the failure processor as its been handled by the callback instead
deliver = false;
}
if (deliver) {
// should deliver to failure processor (either from onException or the dead letter channel)
target = data.failureProcessor != null ? data.failureProcessor : data.deadLetterProcessor;
}
// we should always invoke the deliverToFailureProcessor as it prepares, logs and does a fair
// bit of work for exhausted exchanges (its only the target processor which may be null if handled by a savepoint)
boolean isDeadLetterChannel = isDeadLetterChannel() && (target == null || target == data.deadLetterProcessor);
boolean sync = deliverToFailureProcessor(target, isDeadLetterChannel, exchange, data, callback);
// we are breaking out
return sync;
}
if (data.redeliveryCounter > 0) {
// calculate delay
data.redeliveryDelay = determineRedeliveryDelay(exchange, data.currentRedeliveryPolicy, data.redeliveryDelay, data.redeliveryCounter);
if (data.redeliveryDelay > 0) {
if (data.currentRedeliveryPolicy.isAsyncDelayedRedelivery() && !exchange.isTransacted()) {
// we are doing a redelivery then a thread pool must be configured (see the doStart method)
ObjectHelper.notNull(executorService, "Redelivery is enabled but ExecutorService has not been configured.", this);
// let the RedeliverTask be the logic which tries to redeliver the Exchange which we can used a scheduler to
// have it being executed in the future, or immediately
// we are continuing asynchronously
// mark we are routing async from now and that this redelivery task came from a synchronous routing
data.sync = false;
data.redeliverFromSync = true;
AsyncRedeliveryTask task = new AsyncRedeliveryTask(exchange, callback, data);
// schedule the redelivery task
if (log.isTraceEnabled()) {
log.trace("Scheduling redelivery task to run in {} millis for exchangeId: {}", data.redeliveryDelay, exchange.getExchangeId());
}
executorService.schedule(task, data.redeliveryDelay, TimeUnit.MILLISECONDS);
return false;
} else {
// as the transaction manager requires to execute in the same thread context
try {
// we are doing synchronous redelivery and use thread sleep, so we keep track using a counter how many are sleeping
redeliverySleepCounter.incrementAndGet();
RedeliverSleepTask task = new RedeliverSleepTask(data.currentRedeliveryPolicy, data.redeliveryDelay);
boolean complete = task.sleep();
redeliverySleepCounter.decrementAndGet();
if (!complete) {
// the task was rejected
exchange.setException(new RejectedExecutionException("Redelivery not allowed while stopping"));
// mark the exchange as redelivery exhausted so the failure processor / dead letter channel can process the exchange
exchange.setProperty(Exchange.REDELIVERY_EXHAUSTED, Boolean.TRUE);
// jump to start of loop which then detects that we are failed and exhausted
continue;
}
} catch (InterruptedException e) {
redeliverySleepCounter.decrementAndGet();
// we was interrupted so break out
exchange.setException(e);
// mark the exchange to stop continue routing when interrupted
// as we do not want to continue routing (for example a task has been cancelled)
exchange.setProperty(Exchange.ROUTE_STOP, Boolean.TRUE);
callback.done(data.sync);
return data.sync;
}
}
}
// prepare for redelivery
prepareExchangeForRedelivery(exchange, data);
// letting onRedeliver be executed
deliverToOnRedeliveryProcessor(exchange, data);
// emmit event we are doing redelivery
EventHelper.notifyExchangeRedelivery(exchange.getContext(), exchange, data.redeliveryCounter);
}
// process the exchange (also redelivery)
boolean sync = outputAsync.process(exchange, new AsyncCallback() {
public void done(boolean sync) {
// this callback should only handle the async case
if (sync) {
return;
}
// mark we are in async mode now
data.sync = false;
// if we are done then notify callback and exit
if (isDone(exchange)) {
callback.done(sync);
return;
}
// error occurred so loop back around which we do by invoking the processAsyncErrorHandler
// method which takes care of this in a asynchronous manner
processAsyncErrorHandler(exchange, callback, data);
}
});
if (!sync) {
// the remainder of the Exchange is being processed asynchronously so we should return
return false;
}
// we continue to route synchronously
// if we are done then notify callback and exit
boolean done = isDone(exchange);
if (done) {
callback.done(true);
return true;
}
// error occurred so loop back around.....
}
}
Aggregations