public void process(Exchange exchange) throws Exception { if (output == null) { // no output then just return return; } AsyncProcessorHelper.process(this, exchange); }
private void doProcessParallel(final ProcessorExchangePair pair) throws Exception { final Exchange exchange = pair.getExchange(); Processor processor = pair.getProcessor(); Producer producer = pair.getProducer(); TracedRouteNodes traced = exchange.getUnitOfWork() != null ? exchange.getUnitOfWork().getTracedRouteNodes() : null; // compute time taken if sending to another endpoint StopWatch watch = null; if (producer != null) { watch = new StopWatch(); } try { // prepare tracing starting from a new block if (traced != null) { traced.pushBlock(); } if (producer != null) { EventHelper.notifyExchangeSending(exchange.getContext(), exchange, producer.getEndpoint()); } // let the prepared process it, remember to begin the exchange pair AsyncProcessor async = AsyncProcessorConverterHelper.convert(processor); pair.begin(); // we invoke it synchronously as parallel async routing is too hard AsyncProcessorHelper.process(async, exchange); } finally { pair.done(); // pop the block so by next round we have the same staring point and thus the tracing looks // accurate if (traced != null) { traced.popBlock(); } if (producer != null) { long timeTaken = watch.stop(); Endpoint endpoint = producer.getEndpoint(); // emit event that the exchange was sent to the endpoint // this is okay to do here in the finally block, as the processing is not using the async // routing engine // ( we invoke it synchronously as parallel async routing is too hard) EventHelper.notifyExchangeSent(exchange.getContext(), exchange, endpoint, timeTaken); } } }
public void process(Exchange exchange) throws Exception { AsyncProcessorHelper.process(this, exchange); }
/** All redelivery attempts failed so move the exchange to the dead letter queue */ protected boolean deliverToFailureProcessor( final Processor processor, final Exchange exchange, final RedeliveryData data, final AsyncCallback callback) { boolean sync = true; Exception caught = exchange.getException(); // we did not success with the redelivery so now we let the failure processor handle it // clear exception as we let the failure processor handle it exchange.setException(null); boolean handled = false; // regard both handled or continued as being handled if (shouldHandled(exchange, data) || shouldContinue(exchange, data)) { // its handled then remove traces of redelivery attempted exchange.getIn().removeHeader(Exchange.REDELIVERED); exchange.getIn().removeHeader(Exchange.REDELIVERY_COUNTER); exchange.getIn().removeHeader(Exchange.REDELIVERY_MAX_COUNTER); handled = true; } else { // must decrement the redelivery counter as we didn't process the redelivery but is // handling by the failure handler. So we must -1 to not let the counter be out-of-sync decrementRedeliveryCounter(exchange); } // is the a failure processor to process the Exchange if (processor != null) { // prepare original IN body if it should be moved instead of current body if (data.useOriginalInMessage) { log.trace("Using the original IN message instead of current"); Message original = exchange.getUnitOfWork().getOriginalInMessage(); exchange.setIn(original); if (exchange.hasOut()) { log.trace("Removing the out message to avoid some uncertain behavior"); exchange.setOut(null); } } // reset cached streams so they can be read again MessageHelper.resetStreamCache(exchange.getIn()); log.trace("Failure processor {} is processing Exchange: {}", processor, exchange); // store the last to endpoint as the failure endpoint exchange.setProperty(Exchange.FAILURE_ENDPOINT, exchange.getProperty(Exchange.TO_ENDPOINT)); // the failure processor could also be asynchronous AsyncProcessor afp = AsyncProcessorTypeConverter.convert(processor); sync = AsyncProcessorHelper.process( afp, exchange, new AsyncCallback() { public void done(boolean sync) { log.trace( "Failure processor done: {} processing Exchange: {}", processor, exchange); try { prepareExchangeAfterFailure(exchange, data); // fire event as we had a failure processor to handle it, which there is a event // for boolean deadLetterChannel = processor == data.deadLetterProcessor && data.deadLetterProcessor != null; EventHelper.notifyExchangeFailureHandled( exchange.getContext(), exchange, processor, deadLetterChannel); } finally { // if the fault was handled asynchronously, this should be reflected in the // callback as well data.sync &= sync; callback.done(data.sync); } } }); } else { try { // no processor but we need to prepare after failure as well prepareExchangeAfterFailure(exchange, data); } finally { // callback we are done callback.done(data.sync); } } // create log message String msg = "Failed delivery for exchangeId: " + exchange.getExchangeId(); msg = msg + ". Exhausted after delivery attempt: " + data.redeliveryCounter + " caught: " + caught; if (processor != null) { msg = msg + ". Processed by failure processor: " + processor; } // log that we failed delivery as we are exhausted logFailedDelivery(false, handled, false, exchange, msg, data, null); return sync; }
/** 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; }