org.eclipse.hawkbit.amqp.DelayedRequeueExceptionStrategy Maven / Gradle / Ivy
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.amqp;
import java.util.concurrent.TimeUnit;
import javax.validation.ConstraintViolationException;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler;
import org.springframework.amqp.rabbit.listener.FatalExceptionStrategy;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.messaging.MessageHandlingException;
/**
* Custom {@link FatalExceptionStrategy} that markes defined hawkBit internal
* exceptions not to be requeued. In addition it throttles in case of a requeue
* by means of blocking the processing thread for a certain amount of time. That
* avoids a back and forth between broker and hawkBit at maximum speed.
*
*/
public class DelayedRequeueExceptionStrategy extends ConditionalRejectingErrorHandler.DefaultExceptionStrategy {
private static final Logger LOG = LoggerFactory.getLogger(DelayedRequeueExceptionStrategy.class);
private final long delay;
/**
* @param delay
* in {@link TimeUnit#MILLISECONDS} before requeue.
*/
public DelayedRequeueExceptionStrategy(final long delay) {
this.delay = delay;
}
@Override
protected boolean isUserCauseFatal(final Throwable cause) {
if (invalidMessage(cause)) {
return true;
}
LOG.error("Found a message that has to be requeued. Processing with delay of {}ms: ", delay, cause);
try {
TimeUnit.MILLISECONDS.sleep(delay);
} catch (final InterruptedException e) {
LOG.error("Delay interrupted!", e);
Thread.currentThread().interrupt();
}
return false;
}
private static boolean invalidMessage(final Throwable cause) {
return doesNotExist(cause) || quotaHit(cause) || invalidContent(cause) || invalidState(cause);
}
private static boolean invalidState(final Throwable cause) {
return cause instanceof CancelActionNotAllowedException;
}
private static boolean quotaHit(final Throwable cause) {
return cause instanceof AssignmentQuotaExceededException;
}
private static boolean doesNotExist(final Throwable cause) {
return cause instanceof TenantNotExistException || cause instanceof EntityNotFoundException;
}
private static boolean invalidContent(final Throwable cause) {
return isRepositoryException(cause) || isMessageException(cause);
}
private static boolean isRepositoryException(final Throwable cause) {
return cause instanceof ConstraintViolationException || cause instanceof InvalidTargetAttributeException;
}
private static boolean isMessageException(final Throwable cause) {
return cause instanceof InvalidTargetAddressException || cause instanceof MessageConversionException
|| cause instanceof MessageHandlingException;
}
}