/* * * Copyright 2016 Robert Winkler * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * */ package io.github.resilience4j.retry; import io.github.resilience4j.retry.event.RetryEvent; import io.github.resilience4j.retry.internal.RetryContext; import io.reactivex.Flowable; import io.vavr.CheckedFunction0; import io.vavr.CheckedFunction1; import io.vavr.CheckedRunnable; import java.util.concurrent.Callable; import java.util.function.Function; import java.util.function.Supplier; public interface Retry { /** * Returns the ID of this Retry. * * @return the ID of this Retry */ String getName(); /** * Records a successful call. */ void onSuccess(); /** * Handles a checked exception * * @param exception the exception to handle * @throws Throwable the exception */ void onError(Exception exception) throws Throwable; /** * Handles a runtime exception * * @param runtimeException the exception to handle */ void onRuntimeError(RuntimeException runtimeException); /** * Returns a reactive stream of RetryEvents. * * @return a reactive stream of RetryEvents */ Flowable<RetryEvent> getEventStream(); /** * Creates a Retry with a custom Retry configuration. * * @param name the ID of the Retry * @param retryConfig a custom Retry configuration * * @return a Retry with a custom Retry configuration. */ static RetryContext of(String name, RetryConfig retryConfig){ return new RetryContext(name, retryConfig); } /** * Creates a Retry with a custom Retry configuration. * * @param name the ID of the Retry * @param retryConfigSupplier a supplier of a custom Retry configuration * * @return a Retry with a custom Retry configuration. */ static RetryContext of(String name, Supplier<RetryConfig> retryConfigSupplier){ return new RetryContext(name, retryConfigSupplier.get()); } /** * Creates a Retry with default configuration. * * @param name the ID of the Retry * @return a Retry with default configuration */ static Retry ofDefaults(String name){ return new RetryContext(name, RetryConfig.ofDefaults()); } /** * Decorates and executes the decorated Supplier. * * @param supplier the original Supplier * @param <T> the type of results supplied by this supplier * @return the result of the decorated Supplier. */ default <T> T executeSupplier(Supplier<T> supplier){ return decorateSupplier(this, supplier).get(); } /** * Decorates and executes the decorated Callable. * * @param callable the original Callable * * @return the result of the decorated Callable. * @param <T> the result type of callable * @throws Exception if unable to compute a result */ default <T> T executeCallable(Callable<T> callable) throws Exception{ return decorateCallable(this, callable).call(); } /** * Decorates and executes the decorated Runnable. * * @param runnable the original Runnable */ default void executeRunnable(Runnable runnable){ decorateRunnable(this, runnable).run(); } /** * Creates a retryable supplier. * * @param retryContext the retry context * @param supplier the original function * @param <T> the type of results supplied by this supplier * * @return a retryable function */ static <T> CheckedFunction0<T> decorateCheckedSupplier(Retry retryContext, CheckedFunction0<T> supplier){ return () -> { do try { T result = supplier.apply(); retryContext.onSuccess(); return result; } catch (Exception exception) { retryContext.onError(exception); } while (true); }; } /** * Creates a retryable runnable. * * @param retryContext the retry context * @param runnable the original runnable * * @return a retryable runnable */ static CheckedRunnable decorateCheckedRunnable(Retry retryContext, CheckedRunnable runnable){ return () -> { do try { runnable.run(); retryContext.onSuccess(); break; } catch (Exception exception) { retryContext.onError(exception); } while (true); }; } /** * Creates a retryable function. * * @param retryContext the retry context * @param function the original function * @param <T> the type of the input to the function * @param <R> the result type of the function * * @return a retryable function */ static <T, R> CheckedFunction1<T, R> decorateCheckedFunction(Retry retryContext, CheckedFunction1<T, R> function){ return (T t) -> { do try { R result = function.apply(t); retryContext.onSuccess(); return result; } catch (Exception exception) { retryContext.onError(exception); } while (true); }; } /** * Creates a retryable supplier. * * @param retryContext the retry context * @param supplier the original function * @param <T> the type of results supplied by this supplier * * @return a retryable function */ static <T> Supplier<T> decorateSupplier(Retry retryContext, Supplier<T> supplier){ return () -> { do try { T result = supplier.get(); retryContext.onSuccess(); return result; } catch (RuntimeException runtimeException) { retryContext.onRuntimeError(runtimeException); } while (true); }; } /** * Creates a retryable callable. * * @param retryContext the retry context * @param supplier the original function * @param <T> the type of results supplied by this supplier * * @return a retryable function */ static <T> Callable<T> decorateCallable(Retry retryContext, Callable<T> supplier){ return () -> { do try { T result = supplier.call(); retryContext.onSuccess(); return result; } catch (RuntimeException runtimeException) { retryContext.onRuntimeError(runtimeException); } while (true); }; } /** * Creates a retryable runnable. * * @param retryContext the retry context * @param runnable the original runnable * * @return a retryable runnable */ static Runnable decorateRunnable(Retry retryContext, Runnable runnable){ return () -> { do try { runnable.run(); retryContext.onSuccess(); break; } catch (RuntimeException runtimeException) { retryContext.onRuntimeError(runtimeException); } while (true); }; } /** * Creates a retryable function. * * @param retryContext the retry context * @param function the original function * @param <T> the type of the input to the function * @param <R> the result type of the function * * @return a retryable function */ static <T, R> Function<T, R> decorateFunction(Retry retryContext, Function<T, R> function){ return (T t) -> { do try { R result = function.apply(t); retryContext.onSuccess(); return result; } catch (RuntimeException runtimeException) { retryContext.onRuntimeError(runtimeException); } while (true); }; } /** * Get the Metrics of this RateLimiter. * * @return the Metrics of this RateLimiter */ Metrics getMetrics(); interface Metrics { /** * Returns how many attempts this have been made by this retry. * * @return how many retries have been attempted, but failed. */ int getNumAttempts(); /** * Returns how many retry attempts are allowed before failure. * * @return how many retries are allowed before failure. */ int getMaxAttempts(); } }