Example #1
0
  public synchronized void warmUp() throws Exception {
    if (endpointDone.compareAndSet(false, true)) {
      // endpoints should only be started once as they can be reused on other routes
      // and whatnot, thus their lifecycle is to start once, and only to stop when Camel shutdown
      for (Route route : routes) {
        // ensure endpoint is started first (before the route services, such as the consumer)
        ServiceHelper.startService(route.getEndpoint());
      }
    }

    if (warmUpDone.compareAndSet(false, true)) {

      for (Route route : routes) {
        // warm up the route first
        route.warmUp();

        LOG.debug("Starting services on route: {}", route.getId());
        List<Service> services = route.getServices();

        // callback that we are staring these services
        route.onStartingServices(services);

        // gather list of services to start as we need to start child services as well
        Set<Service> list = new LinkedHashSet<Service>();
        for (Service service : services) {
          list.addAll(ServiceHelper.getChildServices(service));
        }

        // split into consumers and child services as we need to start the consumers
        // afterwards to avoid them being active while the others start
        List<Service> childServices = new ArrayList<Service>();
        for (Service service : list) {

          // inject the route
          if (service instanceof RouteAware) {
            ((RouteAware) service).setRoute(route);
          }

          if (service instanceof Consumer) {
            inputs.put(route, (Consumer) service);
          } else {
            childServices.add(service);
          }
        }
        startChildService(route, childServices);

        // fire event
        EventHelper.notifyRouteAdded(camelContext, route);
      }

      // ensure lifecycle strategy is invoked which among others enlist the route in JMX
      for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
        strategy.onRoutesAdd(routes);
      }

      // add routes to camel context
      camelContext.addRouteCollection(routes);
    }
  }
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);
      }
    }
  }
Example #3
0
  @Override
  protected void doShutdown() throws Exception {
    for (Route route : routes) {
      LOG.debug("Shutting down services on route: {}", route.getId());

      // gather list of services to stop as we need to start child services as well
      Set<Service> services = gatherChildServices(route, true);

      // shutdown services
      stopChildService(route, services, true);

      // shutdown the route itself
      ServiceHelper.stopAndShutdownServices(route);

      // endpoints should only be stopped when Camel is shutting down
      // see more details in the warmUp method
      ServiceHelper.stopAndShutdownServices(route.getEndpoint());
      // invoke callbacks on route policy
      if (route.getRouteContext().getRoutePolicyList() != null) {
        for (RoutePolicy routePolicy : route.getRouteContext().getRoutePolicyList()) {
          routePolicy.onRemove(route);
        }
      }
      // fire event
      EventHelper.notifyRouteRemoved(camelContext, route);
    }

    // need to call onRoutesRemove when the CamelContext is shutting down or Route is shutdown
    for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
      strategy.onRoutesRemove(routes);
    }

    // remove the routes from the inflight registry
    for (Route route : routes) {
      camelContext.getInflightRepository().removeRoute(route.getId());
    }

    // remove the routes from the collections
    camelContext.removeRouteCollection(routes);

    // clear inputs on shutdown
    inputs.clear();
    warmUpDone.set(false);
    endpointDone.set(false);
  }
Example #4
0
  protected void doStop() throws Exception {

    // if we are stopping CamelContext then we are shutting down
    boolean isShutdownCamelContext = camelContext.isStopping();

    if (isShutdownCamelContext || isRemovingRoutes()) {
      // need to call onRoutesRemove when the CamelContext is shutting down or Route is shutdown
      for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
        strategy.onRoutesRemove(routes);
      }
    }

    for (Route route : routes) {
      LOG.debug("Stopping services on route: {}", route.getId());

      // gather list of services to stop as we need to start child services as well
      Set<Service> services = gatherChildServices(route, true);

      // stop services
      stopChildService(route, services, isShutdownCamelContext);

      // stop the route itself
      if (isShutdownCamelContext) {
        ServiceHelper.stopAndShutdownServices(route);
      } else {
        ServiceHelper.stopServices(route);
      }

      // invoke callbacks on route policy
      if (route.getRouteContext().getRoutePolicyList() != null) {
        for (RoutePolicy routePolicy : route.getRouteContext().getRoutePolicyList()) {
          routePolicy.onStop(route);
        }
      }
      // fire event
      EventHelper.notifyRouteStopped(camelContext, route);
    }
    if (isRemovingRoutes()) {
      camelContext.removeRouteCollection(routes);
    }
    // need to warm up again
    warmUpDone.set(false);
  }
Example #5
0
  protected void doStart() throws Exception {
    // ensure we are warmed up before starting the route
    warmUp();

    for (Route route : routes) {
      // start the route itself
      ServiceHelper.startService(route);

      // invoke callbacks on route policy
      if (route.getRouteContext().getRoutePolicyList() != null) {
        for (RoutePolicy routePolicy : route.getRouteContext().getRoutePolicyList()) {
          routePolicy.onStart(route);
        }
      }

      // fire event
      EventHelper.notifyRouteStarted(camelContext, route);
    }
  }
Example #6
0
  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;
  }
  /** 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;
    }