All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zalando.riptide.spring.FailsafePluginFactory Maven / Gradle / Ivy

package org.zalando.riptide.spring;

import net.jodah.failsafe.CircuitBreaker;
import net.jodah.failsafe.RetryPolicy;
import org.zalando.riptide.failsafe.CircuitBreakerListener;
import org.zalando.riptide.failsafe.FailsafePlugin;
import org.zalando.riptide.failsafe.RetryAfterDelayFunction;
import org.zalando.riptide.failsafe.RetryException;
import org.zalando.riptide.failsafe.RetryListener;
import org.zalando.riptide.faults.TransientFaultException;

import javax.annotation.Nullable;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static java.time.Clock.systemUTC;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

@SuppressWarnings("unused")
final class FailsafePluginFactory {

    private FailsafePluginFactory() {

    }

    public static FailsafePlugin createFailsafePlugin(final ScheduledExecutorService scheduler,
            @Nullable final RetryPolicy retryPolicy, @Nullable final CircuitBreaker circuitBreaker,
            final RetryListener listener) {
        return new FailsafePlugin(scheduler)
                .withRetryPolicy(retryPolicy)
                .withCircuitBreaker(circuitBreaker)
                .withListener(listener);
    }

    public static RetryPolicy createRetryPolicy(final RiptideProperties.Retry config) {
        final RetryPolicy policy = new RetryPolicy();

        Optional.ofNullable(config.getFixedDelay())
                .ifPresent(delay -> delay.applyTo(policy::withDelay));

        Optional.ofNullable(config.getBackoff())
                .ifPresent(backoff -> {
                    final TimeSpan delay = backoff.getDelay();
                    final TimeSpan maxDelay = backoff.getMaxDelay();
                    final TimeUnit unit = MILLISECONDS;

                    @Nullable final Double delayFactor = backoff.getDelayFactor();

                    if (delayFactor == null) {
                        policy.withBackoff(delay.to(unit), maxDelay.to(unit), unit);
                    } else {
                        policy.withBackoff(delay.to(unit), maxDelay.to(unit), unit, delayFactor);
                    }
                });

        Optional.ofNullable(config.getMaxRetries())
                .ifPresent(policy::withMaxRetries);

        Optional.ofNullable(config.getMaxDuration())
                .ifPresent(duration -> duration.applyTo(policy::withMaxDuration));

        Optional.ofNullable(config.getJitterFactor())
                .ifPresent(policy::withJitter);

        Optional.ofNullable(config.getJitter())
                .ifPresent(jitter -> jitter.applyTo(policy::withJitter));

        policy.retryOn(TransientFaultException.class);
        policy.retryOn(RetryException.class);
        policy.withDelay(new RetryAfterDelayFunction(systemUTC()));

        return policy;
    }

    public static CircuitBreaker createCircuitBreaker(final RiptideProperties.Client client,
            final CircuitBreakerListener listener) {
        final CircuitBreaker breaker = new CircuitBreaker();

        Optional.ofNullable(client.getTimeout())
                .ifPresent(timeout -> timeout.applyTo(breaker::withTimeout));

        Optional.ofNullable(client.getCircuitBreaker().getFailureThreshold())
                .ifPresent(threshold -> threshold.applyTo(breaker::withFailureThreshold));

        Optional.ofNullable(client.getCircuitBreaker().getDelay())
                .ifPresent(delay -> delay.applyTo(breaker::withDelay));

        Optional.ofNullable(client.getCircuitBreaker().getSuccessThreshold())
                .ifPresent(threshold -> threshold.applyTo(breaker::withSuccessThreshold));

        breaker
                .onOpen(listener::onOpen)
                .onHalfOpen(listener::onHalfOpen)
                .onClose(listener::onClose);

        return breaker;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy