/** Process the exchange using redelivery error handling. */ protected boolean processErrorHandler( final Exchange exchange, final AsyncCallback callback, final RedeliveryData data) { // 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()) { 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); } // 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 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 sync = deliverToFailureProcessor(target, exchange, data, callback); // we are breaking out return sync; } if (data.redeliveryCounter > 0) { // calculate delay data.redeliveryDelay = data.currentRedeliveryPolicy.calculateRedeliveryDelay( data.redeliveryDelay, data.redeliveryCounter); if (data.redeliveryDelay > 0) { // okay there is a delay so create a scheduled task to have it executed in the future if (data.currentRedeliveryPolicy.isAsyncDelayedRedelivery() && !exchange.isTransacted()) { // 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 { // async delayed redelivery was disabled or we are transacted so we must be synchronous // as the transaction manager requires to execute in the same thread context try { data.currentRedeliveryPolicy.sleep(data.redeliveryDelay); } catch (InterruptedException e) { // 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 = AsyncProcessorHelper.process( outputAsync, 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..... } }
public Boolean call() throws Exception { // prepare for redelivery prepareExchangeForRedelivery(exchange, data); // letting onRedeliver be executed at first deliverToOnRedeliveryProcessor(exchange, data); if (log.isTraceEnabled()) { log.trace( "Redelivering exchangeId: {} -> {} for Exchange: {}", new Object[] {exchange.getExchangeId(), outputAsync, exchange}); } // emmit event we are doing redelivery EventHelper.notifyExchangeRedelivery(exchange.getContext(), exchange, data.redeliveryCounter); // process the exchange (also redelivery) boolean sync; if (data.redeliverFromSync) { // this redelivery task was scheduled from synchronous, which we forced to be asynchronous // from // this error handler, which means we have to invoke the callback with false, to have the // callback // be notified when we are done sync = AsyncProcessorHelper.process( outputAsync, exchange, new AsyncCallback() { public void done(boolean doneSync) { log.trace( "Redelivering exchangeId: {} done sync: {}", exchange.getExchangeId(), doneSync); // mark we are in sync mode now data.sync = false; // only process if the exchange hasn't failed // and it has not been handled by the error processor if (isDone(exchange)) { callback.done(false); return; } // error occurred so loop back around which we do by invoking the // processAsyncErrorHandler processAsyncErrorHandler(exchange, callback, data); } }); } else { // this redelivery task was scheduled from asynchronous, which means we should only // handle when the asynchronous task was done sync = AsyncProcessorHelper.process( outputAsync, exchange, new AsyncCallback() { public void done(boolean doneSync) { log.trace( "Redelivering exchangeId: {} done sync: {}", exchange.getExchangeId(), doneSync); // this callback should only handle the async case if (doneSync) { return; } // mark we are in async mode now data.sync = false; // only process if the exchange hasn't failed // and it has not been handled by the error processor if (isDone(exchange)) { callback.done(doneSync); return; } // error occurred so loop back around which we do by invoking the // processAsyncErrorHandler processAsyncErrorHandler(exchange, callback, data); } }); } return sync; }