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); } } }
private boolean doProcessSequential( final Exchange original, final AtomicExchange result, final Iterable<ProcessorExchangePair> pairs, final Iterator<ProcessorExchangePair> it, final ProcessorExchangePair pair, final AsyncCallback callback, final AtomicInteger total) { boolean sync = true; final Exchange exchange = pair.getExchange(); Processor processor = pair.getProcessor(); final Producer producer = pair.getProducer(); TracedRouteNodes traced = exchange.getUnitOfWork() != null ? exchange.getUnitOfWork().getTracedRouteNodes() : null; // compute time taken if sending to another endpoint final StopWatch watch = producer != null ? new StopWatch() : null; 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(); sync = async.process( exchange, new AsyncCallback() { public void done(boolean doneSync) { // we are done with the exchange pair pair.done(); // okay we are done, so notify the exchange was sent if (producer != null) { long timeTaken = watch.stop(); Endpoint endpoint = producer.getEndpoint(); // emit event that the exchange was sent to the endpoint EventHelper.notifyExchangeSent( exchange.getContext(), exchange, endpoint, timeTaken); } // we only have to handle async completion of the routing slip if (doneSync) { return; } // continue processing the multicast asynchronously Exchange subExchange = exchange; // Decide whether to continue with the multicast or not; similar logic to the // Pipeline // remember to test for stop on exception and aggregate before copying back // results boolean continueProcessing = PipelineHelper.continueProcessing( subExchange, "Sequential processing failed for number " + total.get(), LOG); if (stopOnException && !continueProcessing) { if (subExchange.getException() != null) { // wrap in exception to explain where it failed subExchange.setException( new CamelExchangeException( "Sequential processing failed for number " + total, subExchange, subExchange.getException())); } else { // we want to stop on exception, and the exception was handled by the error // handler // this is similar to what the pipeline does, so we should do the same to not // surprise end users // so we should set the failed exchange as the result and be done result.set(subExchange); } // and do the done work doDone(original, subExchange, pairs, callback, false, true); return; } try { doAggregate(getAggregationStrategy(subExchange), result, subExchange); } catch (Throwable e) { // wrap in exception to explain where it failed subExchange.setException( new CamelExchangeException( "Sequential processing failed for number " + total, subExchange, e)); // and do the done work doDone(original, subExchange, pairs, callback, false, true); return; } total.incrementAndGet(); // maybe there are more processors to multicast while (it.hasNext()) { // prepare and run the next ProcessorExchangePair pair = it.next(); subExchange = pair.getExchange(); updateNewExchange(subExchange, total.get(), pairs, it); boolean sync = doProcessSequential(original, result, pairs, it, pair, callback, total); if (!sync) { LOG.trace( "Processing exchangeId: {} is continued being processed asynchronously", original.getExchangeId()); return; } // Decide whether to continue with the multicast or not; similar logic to the // Pipeline // remember to test for stop on exception and aggregate before copying back // results continueProcessing = PipelineHelper.continueProcessing( subExchange, "Sequential processing failed for number " + total.get(), LOG); if (stopOnException && !continueProcessing) { if (subExchange.getException() != null) { // wrap in exception to explain where it failed subExchange.setException( new CamelExchangeException( "Sequential processing failed for number " + total, subExchange, subExchange.getException())); } else { // we want to stop on exception, and the exception was handled by the error // handler // this is similar to what the pipeline does, so we should do the same to // not surprise end users // so we should set the failed exchange as the result and be done result.set(subExchange); } // and do the done work doDone(original, subExchange, pairs, callback, false, true); return; } // must catch any exceptions from aggregation try { doAggregate(getAggregationStrategy(subExchange), result, subExchange); } catch (Throwable e) { // wrap in exception to explain where it failed subExchange.setException( new CamelExchangeException( "Sequential processing failed for number " + total, subExchange, e)); // and do the done work doDone(original, subExchange, pairs, callback, false, true); return; } total.incrementAndGet(); } // do the done work subExchange = result.get() != null ? result.get() : null; doDone(original, subExchange, pairs, callback, false, true); } }); } finally { // pop the block so by next round we have the same staring point and thus the tracing looks // accurate if (traced != null) { traced.popBlock(); } } return sync; }