public void process(Exchange exchange) throws Exception {
   if (output == null) {
     // no output then just return
     return;
   }
   AsyncProcessorHelper.process(this, exchange);
 }
Example #2
0
  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;
    }