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);
}
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();
}
}
Aggregations