diff --git a/src/main/java/com/knecon/fforesight/tenantcommons/TenantsClient.java b/src/main/java/com/knecon/fforesight/tenantcommons/TenantsClient.java index 4bf9947..017c925 100644 --- a/src/main/java/com/knecon/fforesight/tenantcommons/TenantsClient.java +++ b/src/main/java/com/knecon/fforesight/tenantcommons/TenantsClient.java @@ -2,7 +2,6 @@ package com.knecon.fforesight.tenantcommons; import java.util.List; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.HttpStatus; @@ -16,7 +15,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; import com.knecon.fforesight.tenantcommons.model.TenantResponse; import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest; -@FeignClient(name = "TenantsResource", url = "${tenant-user-management-service.url}") +@FeignClient(name = "TenantsResource", url = "${tenant-user-management-service.url}", configuration = TenantsClientConfiguration.class) @ResponseStatus(value = HttpStatus.OK) @ConditionalOnProperty(prefix = "fforesight.tenants", value = "remote", havingValue = "true") public interface TenantsClient extends TenantProvider { diff --git a/src/main/java/com/knecon/fforesight/tenantcommons/TenantsClientConfiguration.java b/src/main/java/com/knecon/fforesight/tenantcommons/TenantsClientConfiguration.java new file mode 100644 index 0000000..81431d7 --- /dev/null +++ b/src/main/java/com/knecon/fforesight/tenantcommons/TenantsClientConfiguration.java @@ -0,0 +1,94 @@ +package com.knecon.fforesight.tenantcommons; + +import java.util.concurrent.TimeUnit; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import feign.RetryableException; +import feign.Retryer; +import lombok.extern.slf4j.Slf4j; + +@Configuration +public class TenantsClientConfiguration { + + public static final int INITIAL_BACKOFF_SECONDS = 15; + public static final int MAX_BACKOFF_MINUTES = 8; + public static final int RETRY_ATTEMPTS = 4; + + + @Bean + public Retryer feignRetryer() { + + return new ExponentialRetryer(TimeUnit.SECONDS.toMillis(INITIAL_BACKOFF_SECONDS), TimeUnit.MINUTES.toMillis(MAX_BACKOFF_MINUTES), RETRY_ATTEMPTS); + } + + + @Slf4j + @SuppressWarnings("PMD.ProperCloneImplementation") + public static class ExponentialRetryer extends Retryer.Default { + + private final long initialPeriod; + private final long maxPeriod; + private final int maxAttempts; + private int attempt = 1; + private long currentPeriod; + + + public ExponentialRetryer(long initialPeriod, long maxPeriod, int maxAttempts) { + + this.initialPeriod = initialPeriod; + this.maxPeriod = maxPeriod; + this.maxAttempts = maxAttempts; + this.currentPeriod = initialPeriod; + } + + + @Override + public void continueOrPropagate(RetryableException e) { + + if (attempt > maxAttempts) { + log.error("Max retry attempts reached. Giving up after {} attempts.", maxAttempts); + throw e; + } + + log.info("Attempt {} - Retrying due to exception: {}", attempt, e.getMessage()); + + long interval; + + if (e.retryAfter() != null) { + interval = e.retryAfter().getTime() - System.currentTimeMillis(); + + if (interval > maxPeriod) { + interval = maxPeriod; + } + + if (interval < 0L) { + return; + } + } else { + interval = currentPeriod; + currentPeriod = Math.min(currentPeriod * 2, maxPeriod); + } + + try { + Thread.sleep(interval); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + throw e; // Rethrow the exception if interrupted + } + + attempt++; + } + + + @Override + public ExponentialRetryer clone() { + + return new ExponentialRetryer(initialPeriod, maxPeriod, maxAttempts); + } + + } + +} + diff --git a/src/main/java/com/knecon/fforesight/tenantcommons/queue/TenantMessagingConfiguration.java b/src/main/java/com/knecon/fforesight/tenantcommons/queue/TenantMessagingConfiguration.java index fd0f720..0d8cdab 100644 --- a/src/main/java/com/knecon/fforesight/tenantcommons/queue/TenantMessagingConfiguration.java +++ b/src/main/java/com/knecon/fforesight/tenantcommons/queue/TenantMessagingConfiguration.java @@ -17,9 +17,9 @@ public abstract class TenantMessagingConfiguration { @Value("${POD_NAME:}") private String podName; - private static final String TENANT_EVENTS_DLQ_SUFFIX = "_tenant_events_dlq"; - private static final String TENANT_CREATED_QUEUE_SUFFIX = "_tenant_created_queue"; - private static final String TENANT_DELETED_QUEUE_SUFFIX = "_tenant_deleted_queue"; + private static final String TENANT_EVENTS_DLQ_SUFFIX = "_tenant_events_error"; + private static final String TENANT_CREATED_QUEUE_SUFFIX = "_tenant_created"; + private static final String TENANT_DELETED_QUEUE_SUFFIX = "_tenant_deleted"; // time in ms after which a deletion will be executed when no consumer is present // see: https://www.rabbitmq.com/docs/ttl#queue-ttl diff --git a/src/main/java/com/knecon/fforesight/tenantcommons/task/ApplicationTaskExecutorBeanConfig.java b/src/main/java/com/knecon/fforesight/tenantcommons/task/ApplicationTaskExecutorBeanConfig.java index 63026e9..b11536c 100644 --- a/src/main/java/com/knecon/fforesight/tenantcommons/task/ApplicationTaskExecutorBeanConfig.java +++ b/src/main/java/com/knecon/fforesight/tenantcommons/task/ApplicationTaskExecutorBeanConfig.java @@ -17,7 +17,7 @@ public class ApplicationTaskExecutorBeanConfig { @Lazy @Bean(name = {APPLICATION_TASK_EXECUTOR_BEAN_NAME, DEFAULT_TASK_EXECUTOR_BEAN_NAME}) - @ConditionalOnMissingBean({ThreadPoolTaskExecutor.class}) + @ConditionalOnMissingBean(name = {APPLICATION_TASK_EXECUTOR_BEAN_NAME, DEFAULT_TASK_EXECUTOR_BEAN_NAME}) public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { return builder.build(); }