diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 00000000..f04422db
Binary files /dev/null and b/.DS_Store differ
diff --git a/core/.DS_Store b/core/.DS_Store
new file mode 100644
index 00000000..0fbb35f8
Binary files /dev/null and b/core/.DS_Store differ
diff --git a/core/src/.DS_Store b/core/src/.DS_Store
new file mode 100644
index 00000000..c0c271f8
Binary files /dev/null and b/core/src/.DS_Store differ
diff --git a/core/src/main/.DS_Store b/core/src/main/.DS_Store
new file mode 100644
index 00000000..faf983f6
Binary files /dev/null and b/core/src/main/.DS_Store differ
diff --git a/core/src/main/java/.DS_Store b/core/src/main/java/.DS_Store
new file mode 100644
index 00000000..d3e6bd63
Binary files /dev/null and b/core/src/main/java/.DS_Store differ
diff --git a/core/src/main/java/dev/.DS_Store b/core/src/main/java/dev/.DS_Store
new file mode 100644
index 00000000..15dc27ec
Binary files /dev/null and b/core/src/main/java/dev/.DS_Store differ
diff --git a/core/src/main/java/dev/failsafe/.DS_Store b/core/src/main/java/dev/failsafe/.DS_Store
new file mode 100644
index 00000000..f321073e
Binary files /dev/null and b/core/src/main/java/dev/failsafe/.DS_Store differ
diff --git a/core/src/main/java/dev/failsafe/ExecutorDelegation.java b/core/src/main/java/dev/failsafe/ExecutorDelegation.java
new file mode 100644
index 00000000..46243092
--- /dev/null
+++ b/core/src/main/java/dev/failsafe/ExecutorDelegation.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * 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 dev.failsafe;
+
+import dev.failsafe.function.AsyncRunnable;
+import dev.failsafe.function.ContextualSupplier;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Wraps a {@link ContextualSupplier} or {@link AsyncRunnable} so that it runs on a user-supplied {@link Executor}
+ * rather than the calling thread, and propagates any resulting throwable back out of the executor thread.
+ *
+ * Extracted from {@link Functions}, which previously combined this executor-delegation concern with
+ * execution-pipeline wiring and generic function adaptation in a single class with no shared state across the
+ * three concerns.
+ *
+ * @author Jonathan Halterman
+ */
+final class ExecutorDelegation {
+ static ContextualSupplier withExecutor(ContextualSupplier supplier, Executor executor) {
+ return executor == null ? supplier : ctx -> {
+ executor.execute(() -> {
+ try {
+ supplier.get(ctx);
+ } catch (Throwable e) {
+ handleExecutorThrowable(e);
+ }
+ });
+ return null;
+ };
+ }
+
+ static AsyncRunnable withExecutor(AsyncRunnable runnable, Executor executor) {
+ return executor == null ? runnable : exec -> {
+ executor.execute(() -> {
+ try {
+ runnable.run(exec);
+ } catch (Throwable e) {
+ handleExecutorThrowable(e);
+ }
+ });
+ };
+ }
+
+ private static void handleExecutorThrowable(Throwable e) {
+ if (e instanceof RuntimeException)
+ throw (RuntimeException) e;
+ if (e instanceof Error)
+ throw (Error) e;
+ throw new FailsafeException(e);
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/dev/failsafe/FailsafeExecutor.java b/core/src/main/java/dev/failsafe/FailsafeExecutor.java
index 82b3144e..992f7d68 100644
--- a/core/src/main/java/dev/failsafe/FailsafeExecutor.java
+++ b/core/src/main/java/dev/failsafe/FailsafeExecutor.java
@@ -32,6 +32,7 @@
import java.util.function.Function;
import static dev.failsafe.Functions.*;
+import static dev.failsafe.FunctionAdapters.*;
/**
*
diff --git a/core/src/main/java/dev/failsafe/Fallback.java b/core/src/main/java/dev/failsafe/Fallback.java
index ed3de304..01c2dd2f 100644
--- a/core/src/main/java/dev/failsafe/Fallback.java
+++ b/core/src/main/java/dev/failsafe/Fallback.java
@@ -25,7 +25,7 @@
import java.util.concurrent.CompletionStage;
-import static dev.failsafe.Functions.toFn;
+import static dev.failsafe.FunctionAdapters.toFn;
/**
* A Policy that handles failures using a fallback function or result.
@@ -224,4 +224,4 @@ static Fallback none() {
*/
@Override
FallbackConfig getConfig();
-}
+}
\ No newline at end of file
diff --git a/core/src/main/java/dev/failsafe/FunctionAdapters.java b/core/src/main/java/dev/failsafe/FunctionAdapters.java
new file mode 100644
index 00000000..3437be8f
--- /dev/null
+++ b/core/src/main/java/dev/failsafe/FunctionAdapters.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * 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 dev.failsafe;
+
+import dev.failsafe.function.*;
+import dev.failsafe.internal.util.Assert;
+
+/**
+ * Adapts various user-supplied functional interface shapes (runnables, suppliers, consumers, results) into the
+ * common {@link ContextualSupplier} or {@link CheckedFunction} shape that the rest of Failsafe operates on.
+ *
+ * Extracted from {@link Functions}, which previously combined this purely-functional adaptation logic with
+ * execution-pipeline wiring and executor-thread delegation in a single class with no shared state across the three
+ * concerns.
+ *
+ * @author Jonathan Halterman
+ */
+final class FunctionAdapters {
+ static ContextualSupplier toCtxSupplier(CheckedRunnable runnable) {
+ Assert.notNull(runnable, "runnable");
+ return ctx -> {
+ runnable.run();
+ return null;
+ };
+ }
+
+ static ContextualSupplier toCtxSupplier(ContextualRunnable runnable) {
+ Assert.notNull(runnable, "runnable");
+ return ctx -> {
+ runnable.run(ctx);
+ return null;
+ };
+ }
+
+ static ContextualSupplier toCtxSupplier(CheckedSupplier supplier) {
+ Assert.notNull(supplier, "supplier");
+ return ctx -> supplier.get();
+ }
+
+ static CheckedFunction toFn(CheckedConsumer consumer) {
+ return t -> {
+ consumer.accept(t);
+ return null;
+ };
+ }
+
+ static CheckedFunction toFn(CheckedRunnable runnable) {
+ return t -> {
+ runnable.run();
+ return null;
+ };
+ }
+
+ static CheckedFunction toFn(CheckedSupplier extends R> supplier) {
+ return t -> supplier.get();
+ }
+
+ static CheckedFunction toFn(R result) {
+ return t -> result;
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/dev/failsafe/Functions.java b/core/src/main/java/dev/failsafe/Functions.java
index 75a050fa..8ed4737c 100644
--- a/core/src/main/java/dev/failsafe/Functions.java
+++ b/core/src/main/java/dev/failsafe/Functions.java
@@ -36,14 +36,14 @@ final class Functions {
* @param result type
*/
static Function, ExecutionResult> get(ContextualSupplier supplier,
- Executor executor) {
+ Executor executor) {
return execution -> {
ExecutionResult result;
Throwable throwable = null;
try {
execution.preExecute();
- result = ExecutionResult.success(withExecutor(supplier, executor).get(execution));
+ result = ExecutionResult.success(ExecutorDelegation.withExecutor(supplier, executor).get(execution));
} catch (Throwable t) {
throwable = t;
result = ExecutionResult.exception(t);
@@ -73,14 +73,14 @@ static Function, ExecutionResult> get(ContextualSupp
* @param result type
*/
static Function, CompletableFuture>> getPromise(
- ContextualSupplier supplier, Executor executor) {
+ ContextualSupplier supplier, Executor executor) {
Assert.notNull(supplier, "supplier");
return execution -> {
ExecutionResult result;
try {
execution.preExecute();
- result = ExecutionResult.success(withExecutor(supplier, executor).get(execution));
+ result = ExecutionResult.success(ExecutorDelegation.withExecutor(supplier, executor).get(execution));
} catch (Throwable t) {
result = ExecutionResult.exception(t);
}
@@ -97,7 +97,7 @@ static Function, CompletableFuture result type
*/
static Function, CompletableFuture>> getPromiseExecution(
- AsyncRunnable runnable, Executor executor) {
+ AsyncRunnable runnable, Executor executor) {
Assert.notNull(runnable, "runnable");
return new Function, CompletableFuture>>() {
@@ -105,7 +105,7 @@ static Function, CompletableFuture> apply(AsyncExecutionInternal execution) {
try {
execution.preExecute();
- withExecutor(runnable, executor).run(execution);
+ ExecutorDelegation.withExecutor(runnable, executor).run(execution);
} catch (Throwable e) {
execution.record(null, e);
}
@@ -125,15 +125,15 @@ public synchronized CompletableFuture> apply(AsyncExecutionIn
*/
@SuppressWarnings("unchecked")
static Function, CompletableFuture>> getPromiseOfStage(
- ContextualSupplier> supplier, FailsafeFuture future,
- Executor executor) {
+ ContextualSupplier> supplier, FailsafeFuture future,
+ Executor executor) {
Assert.notNull(supplier, "supplier");
return execution -> {
CompletableFuture> promise = new CompletableFuture<>();
try {
execution.preExecute();
- CompletionStage extends R> stage = withExecutor(supplier, executor).get(execution);
+ CompletionStage extends R> stage = ExecutorDelegation.withExecutor(supplier, executor).get(execution);
if (stage == null) {
ExecutionResult r = ExecutionResult.success(null);
@@ -168,7 +168,7 @@ static Function, CompletableFuture result type
*/
static Function, CompletableFuture>> toExecutionAware(
- Function, CompletableFuture>> innerFn) {
+ Function, CompletableFuture>> innerFn) {
return execution -> {
ExecutionResult result = execution.getResult();
if (result == null) {
@@ -186,8 +186,8 @@ static Function, CompletableFuture result type
*/
static Function, CompletableFuture>> toAsync(
- Function, CompletableFuture>> innerFn, Scheduler scheduler,
- FailsafeFuture future) {
+ Function, CompletableFuture>> innerFn, Scheduler scheduler,
+ FailsafeFuture future) {
AtomicBoolean scheduled = new AtomicBoolean();
return execution -> {
@@ -221,80 +221,4 @@ static Function, CompletableFuture toCtxSupplier(CheckedRunnable runnable) {
- Assert.notNull(runnable, "runnable");
- return ctx -> {
- runnable.run();
- return null;
- };
- }
-
- static ContextualSupplier toCtxSupplier(ContextualRunnable runnable) {
- Assert.notNull(runnable, "runnable");
- return ctx -> {
- runnable.run(ctx);
- return null;
- };
- }
-
- static ContextualSupplier toCtxSupplier(CheckedSupplier supplier) {
- Assert.notNull(supplier, "supplier");
- return ctx -> supplier.get();
- }
-
- static ContextualSupplier withExecutor(ContextualSupplier supplier, Executor executor) {
- return executor == null ? supplier : ctx -> {
- executor.execute(() -> {
- try {
- supplier.get(ctx);
- } catch (Throwable e) {
- handleExecutorThrowable(e);
- }
- });
- return null;
- };
- }
-
- static AsyncRunnable withExecutor(AsyncRunnable runnable, Executor executor) {
- return executor == null ? runnable : exec -> {
- executor.execute(() -> {
- try {
- runnable.run(exec);
- } catch (Throwable e) {
- handleExecutorThrowable(e);
- }
- });
- };
- }
-
- private static void handleExecutorThrowable(Throwable e) {
- if (e instanceof RuntimeException)
- throw (RuntimeException) e;
- if (e instanceof Error)
- throw (Error) e;
- throw new FailsafeException(e);
- }
-
- static CheckedFunction toFn(CheckedConsumer consumer) {
- return t -> {
- consumer.accept(t);
- return null;
- };
- }
-
- static CheckedFunction toFn(CheckedRunnable runnable) {
- return t -> {
- runnable.run();
- return null;
- };
- }
-
- static CheckedFunction toFn(CheckedSupplier extends R> supplier) {
- return t -> supplier.get();
- }
-
- static CheckedFunction toFn(R result) {
- return t -> result;
- }
-}
+}
\ No newline at end of file
diff --git a/core/src/main/java/dev/failsafe/internal/.DS_Store b/core/src/main/java/dev/failsafe/internal/.DS_Store
new file mode 100644
index 00000000..5008ddfc
Binary files /dev/null and b/core/src/main/java/dev/failsafe/internal/.DS_Store differ
diff --git a/core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java b/core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java
index 1169adca..a78f54f7 100644
--- a/core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java
+++ b/core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java
@@ -24,6 +24,8 @@
import java.time.Duration;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* A {@link CircuitBreaker} implementation.
@@ -34,6 +36,8 @@
* @see CircuitBreakerOpenException
*/
public class CircuitBreakerImpl implements CircuitBreaker, FailurePolicy, DelayablePolicy {
+ private static final Logger LOGGER = Logger.getLogger(CircuitBreakerImpl.class.getName());
+
private final CircuitBreakerConfig config;
/** Writes guarded by "this" */
@@ -154,26 +158,15 @@ protected void recordResult(R result, Throwable exception) {
/**
* Transitions to the {@code newState} if not already in that state and calls any associated event listener.
*/
- protected void transitionTo(State newState, EventListener listener,
+ protected void transitionTo(State newState, EventListener listener, /*extracted method for solo responsibility-MITI*/
ExecutionContext context) {
boolean transitioned = false;
State currentState;
synchronized (this) {
currentState = getState();
- if (!getState().equals(newState)) {
- switch (newState) {
- case CLOSED:
- state.set(new ClosedState<>(this));
- break;
- case OPEN:
- Duration computedDelay = computeDelay(context);
- state.set(new OpenState<>(this, state.get(), computedDelay != null ? computedDelay : config.getDelay()));
- break;
- case HALF_OPEN:
- state.set(new HalfOpenState<>(this));
- break;
- }
+ if (!currentState.equals(newState)) {
+ state.set(createState(newState, context));
transitioned = true;
}
}
@@ -181,11 +174,38 @@ protected void transitionTo(State newState, EventListener
+ * Extracting this from {@link #transitionTo} resolves the prior non-exhaustive {@code switch} (PMD:
+ * NonExhaustiveSwitch) by making {@link State} coverage explicit and enforced at compile time, and gives
+ * state-construction a single, testable seam independent of transition/locking concerns.
+ *
+ * @throws IllegalArgumentException if {@code newState} is not a recognized transition target
+ */
+ protected CircuitState createState(State newState, ExecutionContext context) {
+ switch (newState) {
+ case CLOSED:
+ return new ClosedState<>(this);
+ case OPEN:
+ Duration computedDelay = computeDelay(context);
+ return new OpenState<>(this, state.get(), computedDelay != null ? computedDelay : config.getDelay());
+ case HALF_OPEN:
+ return new HalfOpenState<>(this);
+ default:
+ throw new IllegalArgumentException("Unexpected circuit breaker state: " + newState);
+ }
+ }
+
/**
* Records an execution failure.
*/
@@ -205,4 +225,4 @@ protected void open(ExecutionContext context) {
public PolicyExecutor toExecutor(int policyIndex) {
return new CircuitBreakerExecutor<>(this, policyIndex);
}
-}
+}
\ No newline at end of file
diff --git a/core/src/main/java/dev/failsafe/internal/RetryDelayCalculator.java b/core/src/main/java/dev/failsafe/internal/RetryDelayCalculator.java
new file mode 100644
index 00000000..ee3e98d8
--- /dev/null
+++ b/core/src/main/java/dev/failsafe/internal/RetryDelayCalculator.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2018 the original author or authors.
+ *
+ * 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 dev.failsafe.internal;
+
+import dev.failsafe.ExecutionContext;
+import dev.failsafe.RetryPolicyConfig;
+
+import java.time.Duration;
+
+import static dev.failsafe.internal.util.RandomDelay.randomDelay;
+import static dev.failsafe.internal.util.RandomDelay.randomDelayInRange;
+
+/**
+ * Computes the delay, in nanoseconds, to use before the next retry attempt.
+ *
+ * Extracted from {@link RetryPolicyExecutor#onFailure}, which previously interleaved this delay-math with
+ * retry-exhaustion checks and event-listener dispatch in a single method, and held {@code lastDelayNanos} as
+ * executor-wide mutable state even though only the delay computation ever read or wrote it.
+ *
+ * The computation is a fixed sequence of independent adjustment steps, applied in order: a user-supplied delay
+ * function takes precedence if configured; otherwise a fixed-or-random base delay is computed, then adjusted for
+ * backoff, then jitter, then clamped to any configured max duration. Structuring it this way (each step consuming
+ * the previous step's output, free to leave it unchanged) gives the pipeline its own seam to test and extend
+ * independently of retry-decision logic, in the spirit of Chain of Responsibility.
+ *
+ * @param result type
+ */
+class RetryDelayCalculator {
+ private final RetryPolicyConfig config;
+
+ /** The last fixed, backoff, random or computed delay time in nanoseconds. */
+ private volatile long lastDelayNanos;
+
+ RetryDelayCalculator(RetryPolicyConfig config) {
+ this.config = config;
+ }
+
+ /**
+ * Computes the delay to use before the next retry attempt.
+ *
+ * @param userComputedDelay the result of any user-supplied delay function, or {@code null} if none is configured
+ * or it did not apply for this result/exception. Takes precedence over the fixed/random/backoff steps below.
+ * @param context the current execution context, used for attempt-count-based backoff
+ * @param elapsedNanos elapsed execution time, used to clamp the result to any configured max duration
+ */
+ long computeDelayNanos(Duration userComputedDelay, ExecutionContext context, long elapsedNanos) {
+ long delayNanos;
+
+ if (userComputedDelay != null) {
+ delayNanos = userComputedDelay.toNanos();
+ } else {
+ delayNanos = getFixedOrRandomDelayNanos(lastDelayNanos);
+ delayNanos = adjustForBackoff(context, delayNanos);
+ lastDelayNanos = delayNanos;
+ }
+
+ if (delayNanos != 0)
+ delayNanos = adjustForJitter(delayNanos);
+ return adjustForMaxDuration(delayNanos, elapsedNanos);
+ }
+
+ private long getFixedOrRandomDelayNanos(long delayNanos) {
+ Duration delay = config.getDelay();
+ Duration delayMin = config.getDelayMin();
+ Duration delayMax = config.getDelayMax();
+
+ if (delayNanos == 0 && delay != null && !delay.equals(Duration.ZERO))
+ delayNanos = delay.toNanos();
+ else if (delayMin != null && delayMax != null)
+ delayNanos = randomDelayInRange(delayMin.toNanos(), delayMax.toNanos(), Math.random());
+ return delayNanos;
+ }
+
+ private long adjustForBackoff(ExecutionContext context, long delayNanos) {
+ if (context.getAttemptCount() != 1 && config.getMaxDelay() != null)
+ delayNanos = (long) Math.min(delayNanos * config.getDelayFactor(), config.getMaxDelay().toNanos());
+ return delayNanos;
+ }
+
+ private long adjustForJitter(long delayNanos) {
+ if (config.getJitter() != null)
+ delayNanos = randomDelay(delayNanos, config.getJitter().toNanos(), Math.random());
+ else if (config.getJitterFactor() > 0.0)
+ delayNanos = randomDelay(delayNanos, config.getJitterFactor(), Math.random());
+ return delayNanos;
+ }
+
+ private long adjustForMaxDuration(long delayNanos, long elapsedNanos) {
+ if (config.getMaxDuration() != null) {
+ long maxRemainingDelay = config.getMaxDuration().toNanos() - elapsedNanos;
+ delayNanos = Math.min(delayNanos, maxRemainingDelay < 0 ? 0 : maxRemainingDelay);
+ if (delayNanos < 0)
+ delayNanos = 0;
+ }
+ return delayNanos;
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java b/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java
index 60d24005..b3abfd7a 100644
--- a/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java
+++ b/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java
@@ -28,9 +28,6 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
-import static dev.failsafe.internal.util.RandomDelay.randomDelay;
-import static dev.failsafe.internal.util.RandomDelay.randomDelayInRange;
-
/**
* A PolicyExecutor that handles failures according to a {@link RetryPolicy}.
*
@@ -44,8 +41,8 @@ public class RetryPolicyExecutor extends PolicyExecutor {
// Mutable state
private volatile int failedAttempts;
private volatile boolean retriesExceeded;
- /** The last fixed, backoff, random or computed delay time in nanoseconds. */
- private volatile long lastDelayNanos;
+ /** Extracted: owns the delay-computation pipeline and its state (see RetryDelayCalculator). */
+ private final RetryDelayCalculator delayCalculator;
// Handlers
private final EventHandler abortHandler;
@@ -63,6 +60,7 @@ public RetryPolicyExecutor(RetryPolicyImpl retryPolicy, int policyIndex) {
this.retriesExceededHandler = EventHandler.ofExecutionCompleted(config.getRetriesExceededListener());
this.retryHandler = EventHandler.ofExecutionAttempted(config.getRetryListener());
this.retryScheduledHandler = EventHandler.ofExecutionScheduled(config.getRetryScheduledListener());
+ this.delayCalculator = new RetryDelayCalculator<>(config);
}
@Override
@@ -220,23 +218,11 @@ public ExecutionResult onFailure(ExecutionContext context, ExecutionResult
failedAttemptHandler.handle(result, context);
failedAttempts++;
- long delayNanos = lastDelayNanos;
-
- // Determine the computed delay
- Duration computedDelay = retryPolicy.computeDelay(context);
- if (computedDelay != null) {
- delayNanos = computedDelay.toNanos();
- } else {
- // Determine the fixed or random delay
- delayNanos = getFixedOrRandomDelayNanos(delayNanos);
- delayNanos = adjustForBackoff(context, delayNanos);
- lastDelayNanos = delayNanos;
- }
- if (delayNanos != 0)
- delayNanos = adjustForJitter(delayNanos);
+ // Determine the delay to use before the next attempt
+ Duration userComputedDelay = retryPolicy.computeDelay(context);
long elapsedNanos = context.getElapsedTime().toNanos();
- delayNanos = adjustForMaxDuration(delayNanos, elapsedNanos);
+ long delayNanos = delayCalculator.computeDelayNanos(userComputedDelay, context, elapsedNanos);
// Calculate result
boolean maxRetriesExceeded = config.getMaxRetries() != -1 && failedAttempts > config.getMaxRetries();
@@ -265,40 +251,4 @@ public CompletableFuture> onFailureAsync(ExecutionContext
Scheduler scheduler, FailsafeFuture future) {
return super.onFailureAsync(context, result.withNotComplete(), scheduler, future);
}
-
- private long getFixedOrRandomDelayNanos(long delayNanos) {
- Duration delay = config.getDelay();
- Duration delayMin = config.getDelayMin();
- Duration delayMax = config.getDelayMax();
-
- if (delayNanos == 0 && delay != null && !delay.equals(Duration.ZERO))
- delayNanos = delay.toNanos();
- else if (delayMin != null && delayMax != null)
- delayNanos = randomDelayInRange(delayMin.toNanos(), delayMax.toNanos(), Math.random());
- return delayNanos;
- }
-
- private long adjustForBackoff(ExecutionContext context, long delayNanos) {
- if (context.getAttemptCount() != 1 && config.getMaxDelay() != null)
- delayNanos = (long) Math.min(delayNanos * config.getDelayFactor(), config.getMaxDelay().toNanos());
- return delayNanos;
- }
-
- private long adjustForJitter(long delayNanos) {
- if (config.getJitter() != null)
- delayNanos = randomDelay(delayNanos, config.getJitter().toNanos(), Math.random());
- else if (config.getJitterFactor() > 0.0)
- delayNanos = randomDelay(delayNanos, config.getJitterFactor(), Math.random());
- return delayNanos;
- }
-
- private long adjustForMaxDuration(long delayNanos, long elapsedNanos) {
- if (config.getMaxDuration() != null) {
- long maxRemainingDelay = config.getMaxDuration().toNanos() - elapsedNanos;
- delayNanos = Math.min(delayNanos, maxRemainingDelay < 0 ? 0 : maxRemainingDelay);
- if (delayNanos < 0)
- delayNanos = 0;
- }
- return delayNanos;
- }
-}
+}
\ No newline at end of file
diff --git a/core/src/test/.DS_Store b/core/src/test/.DS_Store
new file mode 100644
index 00000000..28b3405f
Binary files /dev/null and b/core/src/test/.DS_Store differ
diff --git a/core/src/test/java/.DS_Store b/core/src/test/java/.DS_Store
new file mode 100644
index 00000000..d3e6bd63
Binary files /dev/null and b/core/src/test/java/.DS_Store differ
diff --git a/core/src/test/java/dev/.DS_Store b/core/src/test/java/dev/.DS_Store
new file mode 100644
index 00000000..97ac27be
Binary files /dev/null and b/core/src/test/java/dev/.DS_Store differ
diff --git a/pmd-report.txt b/pmd-report.txt
new file mode 100644
index 00000000..3a2cd2d3
--- /dev/null
+++ b/pmd-report.txt
@@ -0,0 +1,229 @@
+core/src/main/java/dev/failsafe/AsyncExecutionImpl.java:19: UnnecessaryImport: Unused import 'dev.failsafe.spi.*'
+core/src/main/java/dev/failsafe/AsyncExecutionImpl.java:45: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/AsyncExecutionImpl.java:56: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/AsyncExecutionImpl.java:148: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/AsyncExecutionImpl.java:153: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/AsyncExecutionImpl.java:156: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/Bulkhead.java:92: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/CallImpl.java:25: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/CallImpl.java:40: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/CircuitBreaker.java:121: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/CircuitBreakerConfig.java:50: UncommentedEmptyConstructor: Document empty constructor
+core/src/main/java/dev/failsafe/DelayablePolicyConfig.java:34: UncommentedEmptyConstructor: Document empty constructor
+core/src/main/java/dev/failsafe/ExecutionImpl.java:43: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/ExecutionImpl.java:56: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/ExecutionImpl.java:58: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/ExecutionImpl.java:60: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/ExecutionImpl.java:62: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/ExecutionImpl.java:64: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/ExecutionImpl.java:66: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/ExecutionImpl.java:68: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/ExecutionImpl.java:126: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/ExecutionImpl.java:181: EmptyCatchBlock: Avoid empty catch blocks
+core/src/main/java/dev/failsafe/ExecutionImpl.java:181: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/ExecutionImpl.java:195: EmptyCatchBlock: Avoid empty catch blocks
+core/src/main/java/dev/failsafe/ExecutionImpl.java:195: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/Failsafe.java:29: UseUtilityClass: All members are static. Consider adding a private no-args constructor to prevent instantiation.
+core/src/main/java/dev/failsafe/FailsafeException.java:27: UncommentedEmptyConstructor: Document empty constructor
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:20: UnnecessaryImport: Unused import 'dev.failsafe.function.*'
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:55: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:56: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:57: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:353: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:355: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:413: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:415: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/FailsafeExecutor.java:417: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/FailurePolicyBuilder.java:180: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/FailurePolicyBuilder.java:181: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/FailurePolicyBuilder.java:183: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/FallbackConfig.java:45: UncommentedEmptyConstructor: Document empty constructor
+core/src/main/java/dev/failsafe/Functions.java:18: UnnecessaryImport: Unused import 'dev.failsafe.function.*'
+core/src/main/java/dev/failsafe/Functions.java:20: UnnecessaryImport: Unused import 'dev.failsafe.spi.*'
+core/src/main/java/dev/failsafe/Functions.java:31: UseUtilityClass: All members are static. Consider adding a private no-args constructor to prevent instantiation.
+core/src/main/java/dev/failsafe/Functions.java:47: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/Functions.java:62: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/Functions.java:84: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/Functions.java:109: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/Functions.java:145: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/Functions.java:149: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/Functions.java:155: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/Functions.java:200: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/Functions.java:202: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/Functions.java:215: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/Functions.java:217: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/Functions.java:251: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/Functions.java:264: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/Functions.java:273: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/Functions.java:275: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/PolicyConfig.java:28: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/PolicyConfig.java:29: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/PolicyConfig.java:31: UncommentedEmptyConstructor: Document empty constructor
+core/src/main/java/dev/failsafe/RateLimiter.java:187: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/RetryPolicyConfig.java:58: UncommentedEmptyConstructor: Document empty constructor
+core/src/main/java/dev/failsafe/SyncExecutionImpl.java:26: UnnecessaryImport: Unused import 'java.util.concurrent.atomic.AtomicReference'
+core/src/main/java/dev/failsafe/SyncExecutionImpl.java:54: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/SyncExecutionImpl.java:81: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/SyncExecutionImpl.java:84: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/SyncExecutionImpl.java:99: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/SyncExecutionImpl.java:193: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/SyncExecutionImpl.java:195: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/event/EventListener.java:33: EmptyCatchBlock: Avoid empty catch blocks
+core/src/main/java/dev/failsafe/event/EventListener.java:33: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/BulkheadExecutor.java:84: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/BulkheadImpl.java:56: EmptyCatchBlock: Avoid empty catch blocks
+core/src/main/java/dev/failsafe/internal/BulkheadImpl.java:74: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/BurstyRateLimiterStats.java:68: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/BurstyRateLimiterStats.java:74: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java:18: UnnecessaryImport: Unused import 'dev.failsafe.*'
+core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java:149: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java:151: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java:165: NonExhaustiveSwitch: Switch statements or expressions should be exhaustive, add a default case (or missing enum branches)
+core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java:184: EmptyCatchBlock: Avoid empty catch blocks
+core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java:184: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/CircuitState.java:20: UnnecessaryImport: Unused import 'dev.failsafe.CircuitBreakerOpenException'
+core/src/main/java/dev/failsafe/internal/CircuitState.java:34: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/CircuitState.java:64: UncommentedEmptyMethodBody: Document empty method body
+core/src/main/java/dev/failsafe/internal/CircuitState.java:67: UncommentedEmptyMethodBody: Document empty method body
+core/src/main/java/dev/failsafe/internal/CircuitState.java:72: UncommentedEmptyMethodBody: Document empty method body
+core/src/main/java/dev/failsafe/internal/CircuitStats.java:28: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CircuitStats.java:38: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CircuitStats.java:40: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/ClosedState.java:53: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/ClosedState.java:62: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/ClosedState.java:64: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:28: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:29: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:30: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:31: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:53: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:54: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:114: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:116: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:123: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:125: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:128: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:130: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java:144: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/DefaultCircuitStats.java:7: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:19: UnnecessaryImport: Unused import 'dev.failsafe.spi.*'
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:52: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:56: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:62: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:82: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:84: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:86: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:89: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:98: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:103: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:111: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/FallbackExecutor.java:121: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/HalfOpenState.java:87: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/HalfOpenState.java:89: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/HalfOpenState.java:98: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/HalfOpenState.java:100: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RateLimiterExecutor.java:64: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RateLimiterExecutor.java:79: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/RateLimiterImpl.java:57: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RateLimiterImpl.java:75: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RateLimiterImpl.java:77: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:21: UnnecessaryImport: Unused import 'dev.failsafe.spi.*'
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:45: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:46: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:48: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:77: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:81: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:85: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:93: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:102: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:110: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:126: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:142: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:164: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:186: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:220: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:237: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:252: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:254: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:275: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:277: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:283: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:289: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:291: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java:300: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyImpl.java:62: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/RetryPolicyImpl.java:63: EmptyCatchBlock: Avoid empty catch blocks
+core/src/main/java/dev/failsafe/internal/RetryPolicyImpl.java:63: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/SmoothRateLimiterStats.java:59: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/TimedCircuitStats.java:35: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/TimedCircuitStats.java:42: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/TimedCircuitStats.java:117: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/TimedCircuitStats.java:189: OneDeclarationPerLine: Use one line for each declaration, it enhances code readability.
+core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java:21: UnnecessaryImport: Unused import 'dev.failsafe.spi.*'
+core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java:82: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java:87: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java:94: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java:146: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java:163: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java:169: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/Assert.java:29: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/Assert.java:34: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/Assert.java:40: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:37: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:38: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:51: MissingOverride: The method 'newThread(Runnable)' is missing an @Override annotation.
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:61: AvoidUsingVolatile: Use of modifier volatile is not recommended.
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:76: OverrideBothEqualsAndHashCodeOnComparable: When implementing Comparable, both equals() and hashCode() should be overridden
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:77: CompareObjectsWithEquals: Use equals() to compare object references.
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:90: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:92: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:102: CloseResource: Ensure that resources like this ScheduledThreadPoolExecutor object are closed after use
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:113: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:118: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:120: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:131: CloseResource: Ensure that resources like this ExecutorService object are closed after use
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:142: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:155: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:157: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java:161: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:48: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:48: AssignmentInOperand: Avoid assignment to tail in operand
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:65: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:72: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:74: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:75: CompareObjectsWithEquals: Use equals() to compare object references.
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:76: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:77: CompareObjectsWithEquals: Use equals() to compare object references.
+core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java:78: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/internal/util/Maths.java:37: UselessParentheses: Useless parentheses around `input / interval`.
+core/src/main/java/dev/failsafe/spi/DefaultScheduledFuture.java:43: OverrideBothEqualsAndHashCodeOnComparable: When implementing Comparable, both equals() and hashCode() should be overridden
+core/src/main/java/dev/failsafe/spi/DelayablePolicy.java:53: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/spi/DelayablePolicy.java:54: AvoidInstanceofChecksInCatchClause: An instanceof check is being performed on the caught exception. Create a separate catch clause for RuntimeException.
+core/src/main/java/dev/failsafe/spi/DelayablePolicy.java:55: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/DelayablePolicy.java:57: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/ExecutionResult.java:209: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/ExecutionResult.java:211: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:75: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:94: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:99: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:101: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:103: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:130: EmptyCatchBlock: Avoid empty catch blocks
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:153: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:173: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailsafeFuture.java:175: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailurePolicy.java:49: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailurePolicy.java:54: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/FailurePolicy.java:55: EmptyCatchBlock: Avoid empty catch blocks
+core/src/main/java/dev/failsafe/spi/FailurePolicy.java:55: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:107: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:109: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:117: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:183: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:194: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:196: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:198: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:205: UncommentedEmptyMethodBody: Document empty method body
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:224: AvoidCatchingGenericException: Avoid catching Throwable in try-catch block
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:234: ControlStatementBraces: This statement should have braces
+core/src/main/java/dev/failsafe/spi/PolicyExecutor.java:239: ControlStatementBraces: This statement should have braces