Search in sources :

Example 46 with AsyncCallback

use of org.apache.camel.AsyncCallback in project camel by apache.

the class RedeliveryErrorHandler method process.

/**
     * Process the exchange using redelivery error handling.
     */
public boolean process(final Exchange exchange, final AsyncCallback callback) {
    final RedeliveryData data = new RedeliveryData();
    // 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(data)) {
            log.trace("Run not allowed, will reject executing exchange: {}", exchange);
            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, isDeadLetterChannel());
            onExceptionOccurred(exchange, data);
        }
        // compute if we are exhausted, and whether redelivery is allowed
        boolean exhausted = isExhausted(exchange, data);
        boolean redeliverAllowed = isRedeliveryAllowed(data);
        // if we are exhausted or redelivery is not allowed, then deliver to failure processor (eg such as DLC)
        if (!redeliverAllowed || 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 isDeadLetterChannel = isDeadLetterChannel() && (target == null || target == data.deadLetterProcessor);
            boolean sync = deliverToFailureProcessor(target, isDeadLetterChannel, exchange, data, callback);
            // we are breaking out
            return sync;
        }
        if (data.redeliveryCounter > 0) {
            // calculate delay
            data.redeliveryDelay = determineRedeliveryDelay(exchange, data.currentRedeliveryPolicy, data.redeliveryDelay, data.redeliveryCounter);
            if (data.redeliveryDelay > 0) {
                if (data.currentRedeliveryPolicy.isAsyncDelayedRedelivery() && !exchange.isTransacted()) {
                    // we are doing a redelivery then a thread pool must be configured (see the doStart method)
                    ObjectHelper.notNull(executorService, "Redelivery is enabled but ExecutorService has not been configured.", this);
                    // 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 {
                    // as the transaction manager requires to execute in the same thread context
                    try {
                        // we are doing synchronous redelivery and use thread sleep, so we keep track using a counter how many are sleeping
                        redeliverySleepCounter.incrementAndGet();
                        RedeliverSleepTask task = new RedeliverSleepTask(data.currentRedeliveryPolicy, data.redeliveryDelay);
                        boolean complete = task.sleep();
                        redeliverySleepCounter.decrementAndGet();
                        if (!complete) {
                            // the task was rejected
                            exchange.setException(new RejectedExecutionException("Redelivery not allowed while stopping"));
                            // mark the exchange as redelivery exhausted so the failure processor / dead letter channel can process the exchange
                            exchange.setProperty(Exchange.REDELIVERY_EXHAUSTED, Boolean.TRUE);
                            // jump to start of loop which then detects that we are failed and exhausted
                            continue;
                        }
                    } catch (InterruptedException e) {
                        redeliverySleepCounter.decrementAndGet();
                        // 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 = outputAsync.process(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.....
    }
}
Also used : Processor(org.apache.camel.Processor) AsyncProcessor(org.apache.camel.AsyncProcessor) AsyncCallback(org.apache.camel.AsyncCallback) SubUnitOfWorkCallback(org.apache.camel.spi.SubUnitOfWorkCallback) RejectedExecutionException(java.util.concurrent.RejectedExecutionException)

Example 47 with AsyncCallback

use of org.apache.camel.AsyncCallback in project camel by apache.

the class TryProcessor method process.

protected boolean process(final Exchange exchange, final AsyncCallback callback, final Iterator<Processor> processors, final AsyncProcessor processor, final Object lastHandled) {
    // this does the actual processing so log at trace level
    LOG.trace("Processing exchangeId: {} >>> {}", exchange.getExchangeId(), exchange);
    // implement asynchronous routing logic in callback so we can have the callback being
    // triggered and then continue routing where we left
    boolean sync = processor.process(exchange, new AsyncCallback() {

        public void done(boolean doneSync) {
            // we only have to handle async completion of the pipeline
            if (doneSync) {
                return;
            }
            // continue processing the try .. catch .. finally asynchronously
            while (continueRouting(processors, exchange)) {
                exchange.setProperty(Exchange.TRY_ROUTE_BLOCK, true);
                ExchangeHelper.prepareOutToIn(exchange);
                // process the next processor
                AsyncProcessor processor = AsyncProcessorConverterHelper.convert(processors.next());
                doneSync = process(exchange, callback, processors, processor, lastHandled);
                if (!doneSync) {
                    LOG.trace("Processing exchangeId: {} is continued being processed asynchronously", exchange.getExchangeId());
                    // so we break out now, then the callback will be invoked which then continue routing from where we left here
                    return;
                }
            }
            ExchangeHelper.prepareOutToIn(exchange);
            exchange.removeProperty(Exchange.TRY_ROUTE_BLOCK);
            exchange.setProperty(Exchange.EXCEPTION_HANDLED, lastHandled);
            LOG.trace("Processing complete for exchangeId: {} >>> {}", exchange.getExchangeId(), exchange);
            callback.done(false);
        }
    });
    return sync;
}
Also used : AsyncProcessor(org.apache.camel.AsyncProcessor) AsyncCallback(org.apache.camel.AsyncCallback)

Example 48 with AsyncCallback

use of org.apache.camel.AsyncCallback in project camel by apache.

the class RoutingSlip method processExchange.

protected boolean processExchange(final Endpoint endpoint, final Exchange exchange, final Exchange original, final AsyncCallback callback, final RoutingSlipIterator iter) {
    // this does the actual processing so log at trace level
    log.trace("Processing exchangeId: {} >>> {}", exchange.getExchangeId(), exchange);
    boolean sync = producerCache.doInAsyncProducer(endpoint, exchange, null, callback, new AsyncProducerCallback() {

        public boolean doInAsyncProducer(Producer producer, AsyncProcessor asyncProducer, final Exchange exchange, ExchangePattern exchangePattern, final AsyncCallback callback) {
            // rework error handling to support fine grained error handling
            RouteContext routeContext = exchange.getUnitOfWork() != null ? exchange.getUnitOfWork().getRouteContext() : null;
            AsyncProcessor target = createErrorHandler(routeContext, exchange, asyncProducer, endpoint);
            // set property which endpoint we send to
            exchange.setProperty(Exchange.TO_ENDPOINT, endpoint.getEndpointUri());
            exchange.setProperty(Exchange.SLIP_ENDPOINT, endpoint.getEndpointUri());
            boolean answer = target.process(exchange, new AsyncCallback() {

                public void done(boolean doneSync) {
                    // we only have to handle async completion of the routing slip
                    if (doneSync) {
                        callback.done(doneSync);
                        return;
                    }
                    // continue processing the routing slip asynchronously
                    Exchange current = prepareExchangeForRoutingSlip(exchange, endpoint);
                    while (iter.hasNext(current)) {
                        // we ignore some kind of exceptions and allow us to continue
                        if (isIgnoreInvalidEndpoints()) {
                            FailedToCreateProducerException e = current.getException(FailedToCreateProducerException.class);
                            if (e != null) {
                                if (log.isDebugEnabled()) {
                                    log.debug("Endpoint uri is invalid: " + endpoint + ". This exception will be ignored.", e);
                                }
                                current.setException(null);
                            }
                        }
                        // check for error if so we should break out
                        if (!continueProcessing(current, "so breaking out of the routing slip", log)) {
                            break;
                        }
                        Endpoint endpoint;
                        try {
                            endpoint = resolveEndpoint(iter, exchange);
                            // if no endpoint was resolved then try the next
                            if (endpoint == null) {
                                continue;
                            }
                        } catch (Exception e) {
                            // error resolving endpoint so we should break out
                            exchange.setException(e);
                            break;
                        }
                        // prepare and process the routing slip
                        boolean sync = processExchange(endpoint, current, original, callback, iter);
                        current = prepareExchangeForRoutingSlip(current, endpoint);
                        if (!sync) {
                            log.trace("Processing exchangeId: {} is continued being processed asynchronously", original.getExchangeId());
                            return;
                        }
                    }
                    // logging nextExchange as it contains the exchange that might have altered the payload and since
                    // we are logging the completion if will be confusing if we log the original instead
                    // we could also consider logging the original and the nextExchange then we have *before* and *after* snapshots
                    log.trace("Processing complete for exchangeId: {} >>> {}", original.getExchangeId(), current);
                    // copy results back to the original exchange
                    ExchangeHelper.copyResults(original, current);
                    if (target instanceof DeadLetterChannel) {
                        Processor deadLetter = ((DeadLetterChannel) target).getDeadLetter();
                        try {
                            ServiceHelper.stopService(deadLetter);
                        } catch (Exception e) {
                            log.warn("Error stopping DeadLetterChannel error handler on routing slip. This exception is ignored.", e);
                        }
                    }
                    callback.done(false);
                }
            });
            // stop error handler if we completed synchronously
            if (answer) {
                if (target instanceof DeadLetterChannel) {
                    Processor deadLetter = ((DeadLetterChannel) target).getDeadLetter();
                    try {
                        ServiceHelper.stopService(deadLetter);
                    } catch (Exception e) {
                        log.warn("Error stopping DeadLetterChannel error handler on routing slip. This exception is ignored.", e);
                    }
                }
            }
            return answer;
        }
    });
    return sync;
}
Also used : Processor(org.apache.camel.Processor) AsyncProcessor(org.apache.camel.AsyncProcessor) AsyncCallback(org.apache.camel.AsyncCallback) FailedToCreateProducerException(org.apache.camel.FailedToCreateProducerException) RouteContext(org.apache.camel.spi.RouteContext) Exchange(org.apache.camel.Exchange) DefaultExchange(org.apache.camel.impl.DefaultExchange) FailedToCreateProducerException(org.apache.camel.FailedToCreateProducerException) AsyncProducerCallback(org.apache.camel.AsyncProducerCallback) Producer(org.apache.camel.Producer) Endpoint(org.apache.camel.Endpoint) ExchangePattern(org.apache.camel.ExchangePattern) AsyncProcessor(org.apache.camel.AsyncProcessor)

Example 49 with AsyncCallback

use of org.apache.camel.AsyncCallback in project camel by apache.

the class SendProcessor method process.

public boolean process(Exchange exchange, final AsyncCallback callback) {
    if (!isStarted()) {
        exchange.setException(new IllegalStateException("SendProcessor has not been started: " + this));
        callback.done(true);
        return true;
    }
    // we should preserve existing MEP so remember old MEP
    // if you want to permanently to change the MEP then use .setExchangePattern in the DSL
    final ExchangePattern existingPattern = exchange.getPattern();
    counter++;
    // if we have a producer then use that as its optimized
    if (producer != null) {
        // record timing for sending the exchange using the producer
        final StopWatch watch = new StopWatch();
        final Exchange target = configureExchange(exchange, pattern);
        EventHelper.notifyExchangeSending(exchange.getContext(), target, destination);
        LOG.debug(">>>> {} {}", destination, exchange);
        boolean sync = true;
        try {
            sync = producer.process(exchange, new AsyncCallback() {

                @Override
                public void done(boolean doneSync) {
                    try {
                        // restore previous MEP
                        target.setPattern(existingPattern);
                        // emit event that the exchange was sent to the endpoint
                        long timeTaken = watch.stop();
                        EventHelper.notifyExchangeSent(target.getContext(), target, destination, timeTaken);
                    } finally {
                        callback.done(doneSync);
                    }
                }
            });
        } catch (Throwable throwable) {
            exchange.setException(throwable);
            callback.done(sync);
        }
        return sync;
    }
    // send the exchange to the destination using the producer cache for the non optimized producers
    return producerCache.doInAsyncProducer(destination, exchange, pattern, callback, new AsyncProducerCallback() {

        public boolean doInAsyncProducer(Producer producer, AsyncProcessor asyncProducer, final Exchange exchange, ExchangePattern pattern, final AsyncCallback callback) {
            final Exchange target = configureExchange(exchange, pattern);
            LOG.debug(">>>> {} {}", destination, exchange);
            return asyncProducer.process(target, new AsyncCallback() {

                public void done(boolean doneSync) {
                    // restore previous MEP
                    target.setPattern(existingPattern);
                    // signal we are done
                    callback.done(doneSync);
                }
            });
        }
    });
}
Also used : Exchange(org.apache.camel.Exchange) AsyncProducerCallback(org.apache.camel.AsyncProducerCallback) Producer(org.apache.camel.Producer) ExchangePattern(org.apache.camel.ExchangePattern) AsyncProcessor(org.apache.camel.AsyncProcessor) AsyncCallback(org.apache.camel.AsyncCallback) StopWatch(org.apache.camel.util.StopWatch)

Example 50 with AsyncCallback

use of org.apache.camel.AsyncCallback in project camel by apache.

the class TraceInterceptor method process.

@Override
public boolean process(final Exchange exchange, final AsyncCallback callback) {
    // do not trace if tracing is disabled
    if (!tracer.isEnabled() || (routeContext != null && !routeContext.isTracing())) {
        return processor.process(exchange, callback);
    }
    // logging TraceEvents to avoid infinite looping
    if (exchange.getProperty(Exchange.TRACE_EVENT, false, Boolean.class)) {
        // but we must still process to allow routing of TraceEvents to eg a JPA endpoint
        return processor.process(exchange, callback);
    }
    final boolean shouldLog = shouldLogNode(node) && shouldLogExchange(exchange);
    // whether we should trace it or not, some nodes should be skipped as they are abstract
    // intermediate steps for instance related to on completion
    boolean trace = true;
    boolean sync = true;
    // okay this is a regular exchange being routed we might need to log and trace
    try {
        // before
        if (shouldLog) {
            // traced holds the information about the current traced route path
            if (exchange.getUnitOfWork() != null) {
                TracedRouteNodes traced = exchange.getUnitOfWork().getTracedRouteNodes();
                if (node instanceof OnCompletionDefinition || node instanceof OnExceptionDefinition) {
                    // skip any of these as its just a marker definition
                    trace = false;
                } else if (ProcessorDefinitionHelper.isFirstChildOfType(OnCompletionDefinition.class, node)) {
                    // special for on completion tracing
                    traceOnCompletion(traced, exchange);
                } else if (ProcessorDefinitionHelper.isFirstChildOfType(OnExceptionDefinition.class, node)) {
                    // special for on exception
                    traceOnException(traced, exchange);
                } else if (ProcessorDefinitionHelper.isFirstChildOfType(CatchDefinition.class, node)) {
                    // special for do catch
                    traceDoCatch(traced, exchange);
                } else if (ProcessorDefinitionHelper.isFirstChildOfType(FinallyDefinition.class, node)) {
                    // special for do finally
                    traceDoFinally(traced, exchange);
                } else if (ProcessorDefinitionHelper.isFirstChildOfType(AggregateDefinition.class, node)) {
                    // special for aggregate
                    traceAggregate(traced, exchange);
                } else {
                    // regular so just add it
                    traced.addTraced(new DefaultRouteNode(node, super.getProcessor()));
                }
            } else {
                LOG.trace("Cannot trace as this Exchange does not have an UnitOfWork: {}", exchange);
            }
        }
        // log and trace the processor
        Object state = null;
        if (shouldLog && trace) {
            logExchange(exchange);
            // either call the in or generic trace method depending on OUT has been enabled or not
            if (tracer.isTraceOutExchanges()) {
                state = traceExchangeIn(exchange);
            } else {
                traceExchange(exchange);
            }
        }
        final Object traceState = state;
        // special for interceptor where we need to keep booking how far we have routed in the intercepted processors
        if (node.getParent() instanceof InterceptDefinition && exchange.getUnitOfWork() != null) {
            TracedRouteNodes traced = exchange.getUnitOfWork().getTracedRouteNodes();
            traceIntercept((InterceptDefinition) node.getParent(), traced, exchange);
        }
        // process the exchange
        sync = processor.process(exchange, new AsyncCallback() {

            @Override
            public void done(boolean doneSync) {
                try {
                    // after (trace out)
                    if (shouldLog && tracer.isTraceOutExchanges()) {
                        logExchange(exchange);
                        traceExchangeOut(exchange, traceState);
                    }
                } catch (Throwable e) {
                    // some exception occurred in trace logic
                    if (shouldLogException(exchange)) {
                        logException(exchange, e);
                    }
                    exchange.setException(e);
                } finally {
                    // ensure callback is always invoked
                    callback.done(doneSync);
                }
            }
        });
    } catch (Throwable e) {
        // some exception occurred in trace logic
        if (shouldLogException(exchange)) {
            logException(exchange, e);
        }
        exchange.setException(e);
    }
    return sync;
}
Also used : CatchDefinition(org.apache.camel.model.CatchDefinition) AsyncCallback(org.apache.camel.AsyncCallback) OnCompletionDefinition(org.apache.camel.model.OnCompletionDefinition) OnExceptionDefinition(org.apache.camel.model.OnExceptionDefinition) AggregateDefinition(org.apache.camel.model.AggregateDefinition) TracedRouteNodes(org.apache.camel.spi.TracedRouteNodes) DefaultRouteNode(org.apache.camel.impl.DefaultRouteNode) InterceptDefinition(org.apache.camel.model.InterceptDefinition)

Aggregations

AsyncCallback (org.apache.camel.AsyncCallback)67 Exchange (org.apache.camel.Exchange)47 AsyncProcessor (org.apache.camel.AsyncProcessor)12 CamelExchangeException (org.apache.camel.CamelExchangeException)8 Message (org.apache.camel.Message)5 Processor (org.apache.camel.Processor)5 CountDownLatch (java.util.concurrent.CountDownLatch)4 RejectedExecutionException (java.util.concurrent.RejectedExecutionException)4 Endpoint (org.apache.camel.Endpoint)4 Producer (org.apache.camel.Producer)4 Synchronization (org.apache.camel.spi.Synchronization)4 StopWatch (org.apache.camel.util.StopWatch)4 InetSocketAddress (java.net.InetSocketAddress)3 HashMap (java.util.HashMap)3 Map (java.util.Map)3 ExchangePattern (org.apache.camel.ExchangePattern)3 ChannelHandler (io.netty.channel.ChannelHandler)2 IOException (java.io.IOException)2 InvocationTargetException (java.lang.reflect.InvocationTargetException)2 ConnectException (java.net.ConnectException)2