Search in sources :

Example 1 with OptimisticLockingAggregationRepository

use of org.apache.camel.spi.OptimisticLockingAggregationRepository in project camel by apache.

the class AggregateProcessor method doStart.

@Override
protected void doStart() throws Exception {
    AggregationStrategy strategy = aggregationStrategy;
    if (strategy instanceof DelegateAggregationStrategy) {
        strategy = ((DelegateAggregationStrategy) strategy).getDelegate();
    }
    if (strategy instanceof PreCompletionAwareAggregationStrategy) {
        preCompletion = true;
        LOG.info("PreCompletionAwareAggregationStrategy detected. Aggregator {} is in pre-completion mode.", getId());
    }
    if (!preCompletion) {
        // if not in pre completion mode then check we configured the completion required
        if (getCompletionTimeout() <= 0 && getCompletionInterval() <= 0 && getCompletionSize() <= 0 && getCompletionPredicate() == null && !isCompletionFromBatchConsumer() && getCompletionTimeoutExpression() == null && getCompletionSizeExpression() == null) {
            throw new IllegalStateException("At least one of the completions options" + " [completionTimeout, completionInterval, completionSize, completionPredicate, completionFromBatchConsumer] must be set");
        }
    }
    if (getCloseCorrelationKeyOnCompletion() != null) {
        if (getCloseCorrelationKeyOnCompletion() > 0) {
            LOG.info("Using ClosedCorrelationKeys with a LRUCache with a capacity of " + getCloseCorrelationKeyOnCompletion());
            closedCorrelationKeys = new LRUCache<String, String>(getCloseCorrelationKeyOnCompletion());
        } else {
            LOG.info("Using ClosedCorrelationKeys with unbounded capacity");
            closedCorrelationKeys = new ConcurrentHashMap<String, String>();
        }
    }
    if (aggregationRepository == null) {
        aggregationRepository = new MemoryAggregationRepository(optimisticLocking);
        LOG.info("Defaulting to MemoryAggregationRepository");
    }
    if (optimisticLocking) {
        if (!(aggregationRepository instanceof OptimisticLockingAggregationRepository)) {
            throw new IllegalArgumentException("Optimistic locking cannot be enabled without using an AggregationRepository that implements OptimisticLockingAggregationRepository");
        }
        LOG.info("Optimistic locking is enabled");
    }
    ServiceHelper.startServices(aggregationStrategy, processor, aggregationRepository);
    // should we use recover checker
    if (aggregationRepository instanceof RecoverableAggregationRepository) {
        RecoverableAggregationRepository recoverable = (RecoverableAggregationRepository) aggregationRepository;
        if (recoverable.isUseRecovery()) {
            long interval = recoverable.getRecoveryIntervalInMillis();
            if (interval <= 0) {
                throw new IllegalArgumentException("AggregationRepository has recovery enabled and the RecoveryInterval option must be a positive number, was: " + interval);
            }
            // create a background recover thread to check every interval
            recoverService = camelContext.getExecutorServiceManager().newScheduledThreadPool(this, "AggregateRecoverChecker", 1);
            Runnable recoverTask = new RecoverTask(recoverable);
            LOG.info("Using RecoverableAggregationRepository by scheduling recover checker to run every " + interval + " millis.");
            // use fixed delay so there is X interval between each run
            recoverService.scheduleWithFixedDelay(recoverTask, 1000L, interval, TimeUnit.MILLISECONDS);
            if (recoverable.getDeadLetterUri() != null) {
                int max = recoverable.getMaximumRedeliveries();
                if (max <= 0) {
                    throw new IllegalArgumentException("Option maximumRedeliveries must be a positive number, was: " + max);
                }
                LOG.info("After " + max + " failed redelivery attempts Exchanges will be moved to deadLetterUri: " + recoverable.getDeadLetterUri());
                // dead letter uri must be a valid endpoint
                Endpoint endpoint = camelContext.getEndpoint(recoverable.getDeadLetterUri());
                if (endpoint == null) {
                    throw new NoSuchEndpointException(recoverable.getDeadLetterUri());
                }
                deadLetterProducerTemplate = camelContext.createProducerTemplate();
            }
        }
    }
    if (getCompletionInterval() > 0 && getCompletionTimeout() > 0) {
        throw new IllegalArgumentException("Only one of completionInterval or completionTimeout can be used, not both.");
    }
    if (getCompletionInterval() > 0) {
        LOG.info("Using CompletionInterval to run every " + getCompletionInterval() + " millis.");
        if (getTimeoutCheckerExecutorService() == null) {
            setTimeoutCheckerExecutorService(camelContext.getExecutorServiceManager().newScheduledThreadPool(this, AGGREGATE_TIMEOUT_CHECKER, 1));
            shutdownTimeoutCheckerExecutorService = true;
        }
        // trigger completion based on interval
        getTimeoutCheckerExecutorService().scheduleAtFixedRate(new AggregationIntervalTask(), getCompletionInterval(), getCompletionInterval(), TimeUnit.MILLISECONDS);
    }
    // start timeout service if its in use
    if (getCompletionTimeout() > 0 || getCompletionTimeoutExpression() != null) {
        LOG.info("Using CompletionTimeout to trigger after " + getCompletionTimeout() + " millis of inactivity.");
        if (getTimeoutCheckerExecutorService() == null) {
            setTimeoutCheckerExecutorService(camelContext.getExecutorServiceManager().newScheduledThreadPool(this, AGGREGATE_TIMEOUT_CHECKER, 1));
            shutdownTimeoutCheckerExecutorService = true;
        }
        // check for timed out aggregated messages once every second
        timeoutMap = new AggregationTimeoutMap(getTimeoutCheckerExecutorService(), 1000L);
        // fill in existing timeout values from the aggregation repository, for example if a restart occurred, then we
        // need to re-establish the timeout map so timeout can trigger
        restoreTimeoutMapFromAggregationRepository();
        ServiceHelper.startService(timeoutMap);
    }
    if (aggregateController == null) {
        aggregateController = new DefaultAggregateController();
    }
    aggregateController.onStart(this);
}
Also used : Endpoint(org.apache.camel.Endpoint) NoSuchEndpointException(org.apache.camel.NoSuchEndpointException) Endpoint(org.apache.camel.Endpoint) RecoverableAggregationRepository(org.apache.camel.spi.RecoverableAggregationRepository) OptimisticLockingAggregationRepository(org.apache.camel.spi.OptimisticLockingAggregationRepository)

Example 2 with OptimisticLockingAggregationRepository

use of org.apache.camel.spi.OptimisticLockingAggregationRepository in project camel by apache.

the class AggregateProcessor method doProcess.

protected void doProcess(Exchange exchange) throws Exception {
    if (getStatistics().isStatisticsEnabled()) {
        totalIn.incrementAndGet();
    }
    //check for the special header to force completion of all groups (and ignore the exchange otherwise)
    boolean completeAllGroups = exchange.getIn().getHeader(Exchange.AGGREGATION_COMPLETE_ALL_GROUPS, false, boolean.class);
    if (completeAllGroups) {
        forceCompletionOfAllGroups();
        return;
    }
    // compute correlation expression
    String key = correlationExpression.evaluate(exchange, String.class);
    if (ObjectHelper.isEmpty(key)) {
        // we have a bad correlation key
        if (isIgnoreInvalidCorrelationKeys()) {
            LOG.debug("Invalid correlation key. This Exchange will be ignored: {}", exchange);
            return;
        } else {
            throw new CamelExchangeException("Invalid correlation key", exchange);
        }
    }
    // is the correlation key closed?
    if (closedCorrelationKeys != null && closedCorrelationKeys.containsKey(key)) {
        throw new ClosedCorrelationKeyException(key, exchange);
    }
    // when optimist locking is enabled we keep trying until we succeed
    if (optimisticLocking) {
        List<Exchange> aggregated = null;
        boolean exhaustedRetries = true;
        int attempt = 0;
        do {
            attempt++;
            // copy exchange, and do not share the unit of work
            // the aggregated output runs in another unit of work
            Exchange copy = ExchangeHelper.createCorrelatedCopy(exchange, false);
            try {
                aggregated = doAggregation(key, copy);
                exhaustedRetries = false;
                break;
            } catch (OptimisticLockingAggregationRepository.OptimisticLockingException e) {
                LOG.trace("On attempt {} OptimisticLockingAggregationRepository: {} threw OptimisticLockingException while trying to add() key: {} and exchange: {}", new Object[] { attempt, aggregationRepository, key, copy, e });
                optimisticLockRetryPolicy.doDelay(attempt);
            }
        } while (optimisticLockRetryPolicy.shouldRetry(attempt));
        if (exhaustedRetries) {
            throw new CamelExchangeException("Exhausted optimistic locking retry attempts, tried " + attempt + " times", exchange, new OptimisticLockingAggregationRepository.OptimisticLockingException());
        } else if (aggregated != null) {
            // we are completed so submit to completion
            for (Exchange agg : aggregated) {
                onSubmitCompletion(key, agg);
            }
        }
    } else {
        // copy exchange, and do not share the unit of work
        // the aggregated output runs in another unit of work
        Exchange copy = ExchangeHelper.createCorrelatedCopy(exchange, false);
        // when memory based then its fast using synchronized, but if the aggregation repository is IO
        // bound such as JPA etc then concurrent aggregation per correlation key could
        // improve performance as we can run aggregation repository get/add in parallel
        List<Exchange> aggregated = null;
        lock.lock();
        try {
            aggregated = doAggregation(key, copy);
        } finally {
            lock.unlock();
        }
        // we are completed so do that work outside the lock
        if (aggregated != null) {
            for (Exchange agg : aggregated) {
                onSubmitCompletion(key, agg);
            }
        }
    }
    // check for the special header to force completion of all groups (inclusive of the message)
    boolean completeAllGroupsInclusive = exchange.getIn().getHeader(Exchange.AGGREGATION_COMPLETE_ALL_GROUPS_INCLUSIVE, false, boolean.class);
    if (completeAllGroupsInclusive) {
        forceCompletionOfAllGroups();
    }
}
Also used : Exchange(org.apache.camel.Exchange) CamelExchangeException(org.apache.camel.CamelExchangeException) OptimisticLockingAggregationRepository(org.apache.camel.spi.OptimisticLockingAggregationRepository) Endpoint(org.apache.camel.Endpoint)

Aggregations

Endpoint (org.apache.camel.Endpoint)2 OptimisticLockingAggregationRepository (org.apache.camel.spi.OptimisticLockingAggregationRepository)2 CamelExchangeException (org.apache.camel.CamelExchangeException)1 Exchange (org.apache.camel.Exchange)1 NoSuchEndpointException (org.apache.camel.NoSuchEndpointException)1 RecoverableAggregationRepository (org.apache.camel.spi.RecoverableAggregationRepository)1