diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 00000000..311a1ecc --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + + dev.failsafe + failsafe-parent + 3.2.2-SNAPSHOT + + + failsafe + Failsafe + + + + + maven-jar-plugin + 3.1.1 + + + + test-jar + + + + + + + diff --git a/src/main/java/dev/failsafe/AsyncExecution.java b/core/src/main/java/dev/failsafe/AsyncExecution.java similarity index 100% rename from src/main/java/dev/failsafe/AsyncExecution.java rename to core/src/main/java/dev/failsafe/AsyncExecution.java diff --git a/src/main/java/dev/failsafe/AsyncExecutionImpl.java b/core/src/main/java/dev/failsafe/AsyncExecutionImpl.java similarity index 100% rename from src/main/java/dev/failsafe/AsyncExecutionImpl.java rename to core/src/main/java/dev/failsafe/AsyncExecutionImpl.java diff --git a/src/main/java/dev/failsafe/Bulkhead.java b/core/src/main/java/dev/failsafe/Bulkhead.java similarity index 100% rename from src/main/java/dev/failsafe/Bulkhead.java rename to core/src/main/java/dev/failsafe/Bulkhead.java diff --git a/src/main/java/dev/failsafe/BulkheadBuilder.java b/core/src/main/java/dev/failsafe/BulkheadBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/BulkheadBuilder.java rename to core/src/main/java/dev/failsafe/BulkheadBuilder.java diff --git a/src/main/java/dev/failsafe/BulkheadConfig.java b/core/src/main/java/dev/failsafe/BulkheadConfig.java similarity index 100% rename from src/main/java/dev/failsafe/BulkheadConfig.java rename to core/src/main/java/dev/failsafe/BulkheadConfig.java diff --git a/src/main/java/dev/failsafe/BulkheadFullException.java b/core/src/main/java/dev/failsafe/BulkheadFullException.java similarity index 100% rename from src/main/java/dev/failsafe/BulkheadFullException.java rename to core/src/main/java/dev/failsafe/BulkheadFullException.java diff --git a/core/src/main/java/dev/failsafe/Call.java b/core/src/main/java/dev/failsafe/Call.java new file mode 100644 index 00000000..7decd279 --- /dev/null +++ b/core/src/main/java/dev/failsafe/Call.java @@ -0,0 +1,47 @@ +/* + * Copyright 2022 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.CheckedRunnable; + +/** + * A call that can perform Failsafe executions and can be cancelled. Cancellations are propagated to any {@link + * ExecutionContext#onCancel(CheckedRunnable) cancelCallback} that is registered. Useful for integrating with libraries + * that support cancellation. + *

+ * To perform cancellable async executions, use the {@link FailsafeExecutor} async methods. + *

+ * + * @param result type + * @author Jonathan Halterman + */ +public interface Call { + /** + * Executes the call until a successful result is returned or the configured policies are exceeded. + * + * @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can + * be used to learn the underlying checked exception. + */ + R execute(); + + /** + * Cancels a synchronous execution by calling the most recent {@link ExecutionContext#onCancel(CheckedRunnable) + * cancelCallback} that was registered during the execution and marking the execution as cancelled. The execution is + * still allowed to complete and return a result. In addition to using a {@link ExecutionContext#onCancel(CheckedRunnable) + * cancelCallback}, executions can cooperate with cancellation by checking {@link ExecutionContext#isCancelled()}. + */ + void cancel(); +} diff --git a/core/src/main/java/dev/failsafe/CallImpl.java b/core/src/main/java/dev/failsafe/CallImpl.java new file mode 100644 index 00000000..b787c8b8 --- /dev/null +++ b/core/src/main/java/dev/failsafe/CallImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright 2022 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; + +/** + * A call implementation that delegates to an execution. + * + * @param result type + * @author Jonathan Halterman + */ +class CallImpl implements Call { + private volatile SyncExecutionImpl execution; + + void setExecution(SyncExecutionImpl execution) { + this.execution = execution; + } + + @Override + public R execute() { + return execution.executeSync(); + } + + @Override + public void cancel() { + execution.cancel(); + } +} diff --git a/src/main/java/dev/failsafe/CircuitBreaker.java b/core/src/main/java/dev/failsafe/CircuitBreaker.java similarity index 100% rename from src/main/java/dev/failsafe/CircuitBreaker.java rename to core/src/main/java/dev/failsafe/CircuitBreaker.java diff --git a/src/main/java/dev/failsafe/CircuitBreakerBuilder.java b/core/src/main/java/dev/failsafe/CircuitBreakerBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/CircuitBreakerBuilder.java rename to core/src/main/java/dev/failsafe/CircuitBreakerBuilder.java diff --git a/src/main/java/dev/failsafe/CircuitBreakerConfig.java b/core/src/main/java/dev/failsafe/CircuitBreakerConfig.java similarity index 100% rename from src/main/java/dev/failsafe/CircuitBreakerConfig.java rename to core/src/main/java/dev/failsafe/CircuitBreakerConfig.java diff --git a/src/main/java/dev/failsafe/CircuitBreakerOpenException.java b/core/src/main/java/dev/failsafe/CircuitBreakerOpenException.java similarity index 100% rename from src/main/java/dev/failsafe/CircuitBreakerOpenException.java rename to core/src/main/java/dev/failsafe/CircuitBreakerOpenException.java diff --git a/src/main/java/dev/failsafe/DelayablePolicyBuilder.java b/core/src/main/java/dev/failsafe/DelayablePolicyBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/DelayablePolicyBuilder.java rename to core/src/main/java/dev/failsafe/DelayablePolicyBuilder.java diff --git a/src/main/java/dev/failsafe/DelayablePolicyConfig.java b/core/src/main/java/dev/failsafe/DelayablePolicyConfig.java similarity index 100% rename from src/main/java/dev/failsafe/DelayablePolicyConfig.java rename to core/src/main/java/dev/failsafe/DelayablePolicyConfig.java diff --git a/src/main/java/dev/failsafe/Execution.java b/core/src/main/java/dev/failsafe/Execution.java similarity index 100% rename from src/main/java/dev/failsafe/Execution.java rename to core/src/main/java/dev/failsafe/Execution.java diff --git a/src/main/java/dev/failsafe/ExecutionContext.java b/core/src/main/java/dev/failsafe/ExecutionContext.java similarity index 86% rename from src/main/java/dev/failsafe/ExecutionContext.java rename to core/src/main/java/dev/failsafe/ExecutionContext.java index 7dd559f1..86cd9a7c 100644 --- a/src/main/java/dev/failsafe/ExecutionContext.java +++ b/core/src/main/java/dev/failsafe/ExecutionContext.java @@ -15,7 +15,10 @@ */ package dev.failsafe; +import dev.failsafe.function.CheckedRunnable; + import java.time.Duration; +import java.util.concurrent.CompletableFuture; /** * Contextual execution information. @@ -24,6 +27,12 @@ * @author Jonathan Halterman */ public interface ExecutionContext { + /** + * Sets the {@code cancelCallback} to be called if the execution is cancelled, such as by the resulting {@link Call} + * or {@link CompletableFuture}, or a {@link Timeout}. Any exception thrown by the {@code cancelCallback} is ignored. + */ + void onCancel(CheckedRunnable cancelCallback); + /** * Returns the elapsed time since initial execution began. */ diff --git a/src/main/java/dev/failsafe/ExecutionImpl.java b/core/src/main/java/dev/failsafe/ExecutionImpl.java similarity index 91% rename from src/main/java/dev/failsafe/ExecutionImpl.java rename to core/src/main/java/dev/failsafe/ExecutionImpl.java index 5e3d3fa6..37366a21 100644 --- a/src/main/java/dev/failsafe/ExecutionImpl.java +++ b/core/src/main/java/dev/failsafe/ExecutionImpl.java @@ -15,6 +15,7 @@ */ package dev.failsafe; +import dev.failsafe.function.CheckedRunnable; import dev.failsafe.internal.util.Assert; import dev.failsafe.spi.ExecutionInternal; import dev.failsafe.spi.ExecutionResult; @@ -53,6 +54,8 @@ class ExecutionImpl implements ExecutionInternal { volatile Duration attemptStartTime; // The index of a PolicyExecutor that cancelled the execution. Integer.MIN_VALUE represents non-cancelled. volatile int cancelledIndex = Integer.MIN_VALUE; + // The user-provided callback to be called when an execution is cancelled + volatile CheckedRunnable cancelCallback; // Whether the execution has pre-executed indicating it has started private volatile boolean preExecuted; // Whether the execution attempt has been recorded @@ -102,6 +105,11 @@ public ExecutionResult getResult() { return result; } + @Override + public void onCancel(CheckedRunnable cancelCallback) { + this.cancelCallback = cancelCallback; + } + @Override public synchronized void preExecute() { if (!preExecuted) { @@ -153,14 +161,30 @@ synchronized ExecutionResult postExecute(ExecutionResult result) { return result; } + /** Called by users. */ @Override public void cancel() { - cancelledIndex = Integer.MAX_VALUE; + if (!isCancelled()) { + cancelledIndex = Integer.MAX_VALUE; + if (cancelCallback != null) { + try { + cancelCallback.run(); + } catch (Throwable ignore) { + } + } + } } + /** Called by policies. */ @Override public void cancel(PolicyExecutor policyExecutor) { cancelledIndex = policyExecutor.getPolicyIndex(); + if (cancelCallback != null) { + try { + cancelCallback.run(); + } catch (Throwable ignore) { + } + } } @Override diff --git a/src/main/java/dev/failsafe/Failsafe.java b/core/src/main/java/dev/failsafe/Failsafe.java similarity index 100% rename from src/main/java/dev/failsafe/Failsafe.java rename to core/src/main/java/dev/failsafe/Failsafe.java diff --git a/src/main/java/dev/failsafe/FailsafeException.java b/core/src/main/java/dev/failsafe/FailsafeException.java similarity index 100% rename from src/main/java/dev/failsafe/FailsafeException.java rename to core/src/main/java/dev/failsafe/FailsafeException.java diff --git a/src/main/java/dev/failsafe/FailsafeExecutor.java b/core/src/main/java/dev/failsafe/FailsafeExecutor.java similarity index 67% rename from src/main/java/dev/failsafe/FailsafeExecutor.java rename to core/src/main/java/dev/failsafe/FailsafeExecutor.java index 421c6435..5fdee059 100644 --- a/src/main/java/dev/failsafe/FailsafeExecutor.java +++ b/core/src/main/java/dev/failsafe/FailsafeExecutor.java @@ -52,7 +52,7 @@ public class FailsafeExecutor { private Executor executor; /** Policies sorted outer-most first */ final List> policies; - private EventHandler completeHandler; + private volatile EventHandler completeHandler; private volatile EventHandler failureHandler; private volatile EventHandler successHandler; @@ -105,11 +105,8 @@ public

> FailsafeExecutor compose(P innerPolicy) { * Executes the {@code supplier} until a successful result is returned or the configured policies are exceeded. * * @throws NullPointerException if the {@code supplier} is null - * @throws FailsafeException if the {@code supplier} fails with a checked Exception. {@link - * FailsafeException#getCause()} can be used to learn the underlying checked exception - * @throws TimeoutExceededException if the execution fails because a {@link Timeout} is exceeded. - * @throws CircuitBreakerOpenException if the execution fails because a {@link CircuitBreaker} is open. - * @throws RateLimitExceededException if the execution fails because a {@link RateLimiter} is exceeded. + * @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can + * be used to learn the underlying checked exception. */ public T get(CheckedSupplier supplier) { return call(toCtxSupplier(supplier)); @@ -119,27 +116,36 @@ public T get(CheckedSupplier supplier) { * Executes the {@code supplier} until a successful result is returned or the configured policies are exceeded. * * @throws NullPointerException if the {@code supplier} is null - * @throws FailsafeException if the {@code supplier} fails with a checked Exception. {@link - * FailsafeException#getCause()} can be used to learn the underlying checked exception - * @throws TimeoutExceededException if the execution fails because a {@link Timeout} is exceeded. - * @throws CircuitBreakerOpenException if the execution fails because a {@link CircuitBreaker} is open. - * @throws RateLimitExceededException if the execution fails because a {@link RateLimiter} is exceeded. + * @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can + * be used to learn the underlying checked exception. */ public T get(ContextualSupplier supplier) { return call(Assert.notNull(supplier, "supplier")); } + /** + * Returns a call that can execute the {@code supplier} until a successful result is returned or the configured + * policies are exceeded. + * + * @throws NullPointerException if the {@code supplier} is null + */ + public Call getCall(ContextualRunnable runnable) { + return callSync(toCtxSupplier(runnable)); + } + + /** + * Returns a call that can execute the {@code supplier} until a successful result is returned or the configured + * policies are exceeded. + * + * @throws NullPointerException if the {@code supplier} is null + */ + public Call getCall(ContextualSupplier supplier) { + return callSync(Assert.notNull(supplier, "supplier")); + } + /** * Executes the {@code supplier} asynchronously until a successful result is returned or the configured policies are * exceeded. - *

    - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @throws NullPointerException if the {@code supplier} is null * @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution @@ -151,14 +157,6 @@ public CompletableFuture getAsync(CheckedSupplier supplier) /** * Executes the {@code supplier} asynchronously until a successful result is returned or the configured policies are * exceeded. - *
    - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @throws NullPointerException if the {@code supplier} is null * @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution @@ -176,14 +174,6 @@ public CompletableFuture getAsync(ContextualSupplier supp * completed. Any exception that is thrown from the {@code runnable} will automatically be recorded via {@link * AsyncExecution#recordException(Throwable)}. *

- *
    - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @throws NullPointerException if the {@code supplier} is null * @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution @@ -197,14 +187,6 @@ public CompletableFuture getAsyncExecution(AsyncRunnable run * policies are exceeded. *

Cancelling the resulting {@link CompletableFuture} will automatically cancels the supplied {@link * CompletionStage} if it's a {@link Future}.

- *
    - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @throws NullPointerException if the {@code supplier} is null * @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution @@ -218,15 +200,6 @@ public CompletableFuture getStageAsync(CheckedSupplierCancelling the resulting {@link CompletableFuture} will automatically cancels the supplied {@link * CompletionStage} if it's a {@link Future}.

- *
    - *
  • If the {@code supplier} returns {@code null}, the execution attempt will record a {@code null} result.
  • - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @throws NullPointerException if the {@code supplier} is null * @throws RejectedExecutionException if the {@code supplier} cannot be scheduled for execution @@ -240,11 +213,8 @@ public CompletableFuture getStageAsync( * Executes the {@code runnable} until successful or until the configured policies are exceeded. * * @throws NullPointerException if the {@code runnable} is null - * @throws FailsafeException if the {@code runnable} fails with a checked Exception. {@link - * FailsafeException#getCause()} can be used to learn the underlying checked exception - * @throws TimeoutExceededException if the execution fails because a {@link Timeout} is exceeded. - * @throws CircuitBreakerOpenException if the execution fails because a {@link CircuitBreaker} is open. - * @throws RateLimitExceededException if the execution fails because a {@link RateLimiter} is exceeded. + * @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can + * be used to learn the underlying checked exception. */ public void run(CheckedRunnable runnable) { call(toCtxSupplier(runnable)); @@ -254,11 +224,8 @@ public void run(CheckedRunnable runnable) { * Executes the {@code runnable} until successful or until the configured policies are exceeded. * * @throws NullPointerException if the {@code runnable} is null - * @throws FailsafeException if the {@code runnable} fails with a checked Exception. {@link - * FailsafeException#getCause()} can be used to learn the underlying checked exception - * @throws TimeoutExceededException if the execution fails because a {@link Timeout} is exceeded. - * @throws CircuitBreakerOpenException if the execution fails because a {@link CircuitBreaker} is open. - * @throws RateLimitExceededException if the execution fails because a {@link RateLimiter} is exceeded. + * @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can + * be used to learn the underlying checked exception. */ public void run(ContextualRunnable runnable) { call(toCtxSupplier(runnable)); @@ -266,14 +233,6 @@ public void run(ContextualRunnable runnable) { /** * Executes the {@code runnable} asynchronously until successful or until the configured policies are exceeded. - *
    - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @throws NullPointerException if the {@code runnable} is null * @throws RejectedExecutionException if the {@code runnable} cannot be scheduled for execution @@ -284,14 +243,6 @@ public CompletableFuture runAsync(CheckedRunnable runnable) { /** * Executes the {@code runnable} asynchronously until successful or until the configured policies are exceeded. - *
    - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @throws NullPointerException if the {@code runnable} is null * @throws RejectedExecutionException if the {@code runnable} cannot be scheduled for execution @@ -309,14 +260,6 @@ public CompletableFuture runAsync(ContextualRunnable runnable) { * completed. Any exception that is thrown from the {@code runnable} will automatically be recorded via {@link * AsyncExecution#recordException(Throwable)}. *

- *
    - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @throws NullPointerException if the {@code runnable} is null * @throws RejectedExecutionException if the {@code runnable} cannot be scheduled for execution @@ -425,39 +368,28 @@ public FailsafeExecutor with(Scheduler scheduler) { /** * Calls the {@code innerSupplier} synchronously, handling results according to the configured policies. - * - * @throws FailsafeException if the {@code innerSupplier} fails with a checked Exception or if interrupted while - * waiting to perform a retry. - * @throws TimeoutExceededException if the execution fails because a {@link Timeout} is exceeded. - * @throws CircuitBreakerOpenException if the execution fails because a {@link CircuitBreaker} is open. - * @throws RateLimitExceededException if the execution fails because a {@link RateLimiter} is exceeded. */ @SuppressWarnings({ "unchecked", "rawtypes" }) private T call(ContextualSupplier innerSupplier) { - SyncExecutionImpl execution = new SyncExecutionImpl(this, scheduler, Functions.get(innerSupplier, executor)); - ExecutionResult result = execution.executeSync(); - Throwable exception = result.getException(); - if (exception != null) { - if (exception instanceof RuntimeException) - throw (RuntimeException) exception; - if (exception instanceof Error) - throw (Error) exception; - throw new FailsafeException(exception); - } - return result.getResult(); + SyncExecutionImpl execution = new SyncExecutionImpl(this, scheduler, null, + Functions.get(innerSupplier, executor)); + return execution.executeSync(); + } + + /** + * Returns a Call that calls the {@code innerSupplier} synchronously, handling results according to the configured + * policies. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + private Call callSync(ContextualSupplier innerSupplier) { + CallImpl call = new CallImpl<>(); + new SyncExecutionImpl(this, scheduler, call, Functions.get(innerSupplier, executor)); + return call; } /** * Calls the asynchronous {@code innerFn} via the configured Scheduler, handling results according to the configured * policies. - *
    - *
  • If the execution fails because a {@link Timeout} is exceeded, the resulting future is completed exceptionally - * with {@link TimeoutExceededException}.
  • - *
  • If the execution fails because a {@link CircuitBreaker} is open, the resulting future is completed - * exceptionally with {@link CircuitBreakerOpenException}.
  • - *
  • If the execution fails because a {@link RateLimiter} is exceeded, the resulting future is completed - * exceptionally with {@link RateLimitExceededException}.
  • - *
* * @param asyncExecution whether this is a detached, async execution that must be manually completed * @throws NullPointerException if the {@code innerFn} is null diff --git a/src/main/java/dev/failsafe/FailurePolicyBuilder.java b/core/src/main/java/dev/failsafe/FailurePolicyBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/FailurePolicyBuilder.java rename to core/src/main/java/dev/failsafe/FailurePolicyBuilder.java diff --git a/src/main/java/dev/failsafe/FailurePolicyConfig.java b/core/src/main/java/dev/failsafe/FailurePolicyConfig.java similarity index 100% rename from src/main/java/dev/failsafe/FailurePolicyConfig.java rename to core/src/main/java/dev/failsafe/FailurePolicyConfig.java diff --git a/src/main/java/dev/failsafe/Fallback.java b/core/src/main/java/dev/failsafe/Fallback.java similarity index 100% rename from src/main/java/dev/failsafe/Fallback.java rename to core/src/main/java/dev/failsafe/Fallback.java diff --git a/src/main/java/dev/failsafe/FallbackBuilder.java b/core/src/main/java/dev/failsafe/FallbackBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/FallbackBuilder.java rename to core/src/main/java/dev/failsafe/FallbackBuilder.java diff --git a/src/main/java/dev/failsafe/FallbackConfig.java b/core/src/main/java/dev/failsafe/FallbackConfig.java similarity index 100% rename from src/main/java/dev/failsafe/FallbackConfig.java rename to core/src/main/java/dev/failsafe/FallbackConfig.java diff --git a/src/main/java/dev/failsafe/Functions.java b/core/src/main/java/dev/failsafe/Functions.java similarity index 100% rename from src/main/java/dev/failsafe/Functions.java rename to core/src/main/java/dev/failsafe/Functions.java diff --git a/src/main/java/dev/failsafe/Policy.java b/core/src/main/java/dev/failsafe/Policy.java similarity index 100% rename from src/main/java/dev/failsafe/Policy.java rename to core/src/main/java/dev/failsafe/Policy.java diff --git a/src/main/java/dev/failsafe/PolicyBuilder.java b/core/src/main/java/dev/failsafe/PolicyBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/PolicyBuilder.java rename to core/src/main/java/dev/failsafe/PolicyBuilder.java diff --git a/src/main/java/dev/failsafe/PolicyConfig.java b/core/src/main/java/dev/failsafe/PolicyConfig.java similarity index 100% rename from src/main/java/dev/failsafe/PolicyConfig.java rename to core/src/main/java/dev/failsafe/PolicyConfig.java diff --git a/src/main/java/dev/failsafe/PolicyListeners.java b/core/src/main/java/dev/failsafe/PolicyListeners.java similarity index 100% rename from src/main/java/dev/failsafe/PolicyListeners.java rename to core/src/main/java/dev/failsafe/PolicyListeners.java diff --git a/src/main/java/dev/failsafe/RateLimitExceededException.java b/core/src/main/java/dev/failsafe/RateLimitExceededException.java similarity index 100% rename from src/main/java/dev/failsafe/RateLimitExceededException.java rename to core/src/main/java/dev/failsafe/RateLimitExceededException.java diff --git a/src/main/java/dev/failsafe/RateLimiter.java b/core/src/main/java/dev/failsafe/RateLimiter.java similarity index 100% rename from src/main/java/dev/failsafe/RateLimiter.java rename to core/src/main/java/dev/failsafe/RateLimiter.java diff --git a/src/main/java/dev/failsafe/RateLimiterBuilder.java b/core/src/main/java/dev/failsafe/RateLimiterBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/RateLimiterBuilder.java rename to core/src/main/java/dev/failsafe/RateLimiterBuilder.java diff --git a/src/main/java/dev/failsafe/RateLimiterConfig.java b/core/src/main/java/dev/failsafe/RateLimiterConfig.java similarity index 100% rename from src/main/java/dev/failsafe/RateLimiterConfig.java rename to core/src/main/java/dev/failsafe/RateLimiterConfig.java diff --git a/src/main/java/dev/failsafe/RetryPolicy.java b/core/src/main/java/dev/failsafe/RetryPolicy.java similarity index 100% rename from src/main/java/dev/failsafe/RetryPolicy.java rename to core/src/main/java/dev/failsafe/RetryPolicy.java diff --git a/src/main/java/dev/failsafe/RetryPolicyBuilder.java b/core/src/main/java/dev/failsafe/RetryPolicyBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/RetryPolicyBuilder.java rename to core/src/main/java/dev/failsafe/RetryPolicyBuilder.java diff --git a/src/main/java/dev/failsafe/RetryPolicyConfig.java b/core/src/main/java/dev/failsafe/RetryPolicyConfig.java similarity index 100% rename from src/main/java/dev/failsafe/RetryPolicyConfig.java rename to core/src/main/java/dev/failsafe/RetryPolicyConfig.java diff --git a/src/main/java/dev/failsafe/SyncExecutionImpl.java b/core/src/main/java/dev/failsafe/SyncExecutionImpl.java similarity index 88% rename from src/main/java/dev/failsafe/SyncExecutionImpl.java rename to core/src/main/java/dev/failsafe/SyncExecutionImpl.java index 2cc465a5..af90bb2b 100644 --- a/src/main/java/dev/failsafe/SyncExecutionImpl.java +++ b/core/src/main/java/dev/failsafe/SyncExecutionImpl.java @@ -17,8 +17,8 @@ import dev.failsafe.spi.ExecutionResult; import dev.failsafe.spi.PolicyExecutor; -import dev.failsafe.spi.SyncExecutionInternal; import dev.failsafe.spi.Scheduler; +import dev.failsafe.spi.SyncExecutionInternal; import java.time.Duration; import java.util.List; @@ -35,6 +35,8 @@ final class SyncExecutionImpl extends ExecutionImpl implements SyncExecuti // An optional Failsafe executor private final FailsafeExecutor executor; + // An optoinal Failsafe call + private final CallImpl call; // The outer-most function that executions begin with private Function, ExecutionResult> outerFn; // Whether the execution is currently interruptable @@ -55,6 +57,7 @@ final class SyncExecutionImpl extends ExecutionImpl implements SyncExecuti SyncExecutionImpl(List> policies) { super(policies); executor = null; + call = null; initial = this; preExecute(); } @@ -62,11 +65,14 @@ final class SyncExecutionImpl extends ExecutionImpl implements SyncExecuti /** * Create a sync execution for the {@code executor}. */ - SyncExecutionImpl(FailsafeExecutor executor, Scheduler scheduler, + SyncExecutionImpl(FailsafeExecutor executor, Scheduler scheduler, CallImpl call, Function, ExecutionResult> innerFn) { super(executor.policies); this.executor = executor; + this.call = call; initial = this; + if (call != null) + call.setExecution(this); outerFn = innerFn; for (PolicyExecutor policyExecutor : policyExecutors) @@ -79,9 +85,12 @@ final class SyncExecutionImpl extends ExecutionImpl implements SyncExecuti private SyncExecutionImpl(SyncExecutionImpl execution) { super(execution); executor = execution.executor; + call = execution.call; interruptable = execution.interruptable; interrupted = execution.interrupted; initial = execution.initial; + if (call != null) + call.setExecution(this); } @Override @@ -178,10 +187,18 @@ public SyncExecutionImpl copy() { /** * Performs a synchronous execution. */ - ExecutionResult executeSync() { + R executeSync() { ExecutionResult result = outerFn.apply(this); completed = result.isComplete(); executor.completionHandler.accept(result, this); - return result; + Throwable exception = result.getException(); + if (exception != null) { + if (exception instanceof RuntimeException) + throw (RuntimeException) exception; + if (exception instanceof Error) + throw (Error) exception; + throw new FailsafeException(exception); + } + return result.getResult(); } } diff --git a/src/main/java/dev/failsafe/Timeout.java b/core/src/main/java/dev/failsafe/Timeout.java similarity index 100% rename from src/main/java/dev/failsafe/Timeout.java rename to core/src/main/java/dev/failsafe/Timeout.java diff --git a/src/main/java/dev/failsafe/TimeoutBuilder.java b/core/src/main/java/dev/failsafe/TimeoutBuilder.java similarity index 100% rename from src/main/java/dev/failsafe/TimeoutBuilder.java rename to core/src/main/java/dev/failsafe/TimeoutBuilder.java diff --git a/src/main/java/dev/failsafe/TimeoutConfig.java b/core/src/main/java/dev/failsafe/TimeoutConfig.java similarity index 100% rename from src/main/java/dev/failsafe/TimeoutConfig.java rename to core/src/main/java/dev/failsafe/TimeoutConfig.java diff --git a/src/main/java/dev/failsafe/TimeoutExceededException.java b/core/src/main/java/dev/failsafe/TimeoutExceededException.java similarity index 100% rename from src/main/java/dev/failsafe/TimeoutExceededException.java rename to core/src/main/java/dev/failsafe/TimeoutExceededException.java diff --git a/src/main/java/dev/failsafe/event/CircuitBreakerStateChangedEvent.java b/core/src/main/java/dev/failsafe/event/CircuitBreakerStateChangedEvent.java similarity index 100% rename from src/main/java/dev/failsafe/event/CircuitBreakerStateChangedEvent.java rename to core/src/main/java/dev/failsafe/event/CircuitBreakerStateChangedEvent.java diff --git a/src/main/java/dev/failsafe/event/EventListener.java b/core/src/main/java/dev/failsafe/event/EventListener.java similarity index 100% rename from src/main/java/dev/failsafe/event/EventListener.java rename to core/src/main/java/dev/failsafe/event/EventListener.java diff --git a/src/main/java/dev/failsafe/event/ExecutionAttemptedEvent.java b/core/src/main/java/dev/failsafe/event/ExecutionAttemptedEvent.java similarity index 100% rename from src/main/java/dev/failsafe/event/ExecutionAttemptedEvent.java rename to core/src/main/java/dev/failsafe/event/ExecutionAttemptedEvent.java diff --git a/src/main/java/dev/failsafe/event/ExecutionCompletedEvent.java b/core/src/main/java/dev/failsafe/event/ExecutionCompletedEvent.java similarity index 100% rename from src/main/java/dev/failsafe/event/ExecutionCompletedEvent.java rename to core/src/main/java/dev/failsafe/event/ExecutionCompletedEvent.java diff --git a/src/main/java/dev/failsafe/event/ExecutionEvent.java b/core/src/main/java/dev/failsafe/event/ExecutionEvent.java similarity index 100% rename from src/main/java/dev/failsafe/event/ExecutionEvent.java rename to core/src/main/java/dev/failsafe/event/ExecutionEvent.java diff --git a/src/main/java/dev/failsafe/event/ExecutionScheduledEvent.java b/core/src/main/java/dev/failsafe/event/ExecutionScheduledEvent.java similarity index 100% rename from src/main/java/dev/failsafe/event/ExecutionScheduledEvent.java rename to core/src/main/java/dev/failsafe/event/ExecutionScheduledEvent.java diff --git a/src/main/java/dev/failsafe/event/package-info.java b/core/src/main/java/dev/failsafe/event/package-info.java similarity index 100% rename from src/main/java/dev/failsafe/event/package-info.java rename to core/src/main/java/dev/failsafe/event/package-info.java diff --git a/src/main/java/dev/failsafe/function/AsyncRunnable.java b/core/src/main/java/dev/failsafe/function/AsyncRunnable.java similarity index 100% rename from src/main/java/dev/failsafe/function/AsyncRunnable.java rename to core/src/main/java/dev/failsafe/function/AsyncRunnable.java diff --git a/src/main/java/dev/failsafe/function/AsyncSupplier.java b/core/src/main/java/dev/failsafe/function/AsyncSupplier.java similarity index 100% rename from src/main/java/dev/failsafe/function/AsyncSupplier.java rename to core/src/main/java/dev/failsafe/function/AsyncSupplier.java diff --git a/src/main/java/dev/failsafe/function/CheckedBiPredicate.java b/core/src/main/java/dev/failsafe/function/CheckedBiPredicate.java similarity index 100% rename from src/main/java/dev/failsafe/function/CheckedBiPredicate.java rename to core/src/main/java/dev/failsafe/function/CheckedBiPredicate.java diff --git a/src/main/java/dev/failsafe/function/CheckedConsumer.java b/core/src/main/java/dev/failsafe/function/CheckedConsumer.java similarity index 100% rename from src/main/java/dev/failsafe/function/CheckedConsumer.java rename to core/src/main/java/dev/failsafe/function/CheckedConsumer.java diff --git a/src/main/java/dev/failsafe/function/CheckedFunction.java b/core/src/main/java/dev/failsafe/function/CheckedFunction.java similarity index 100% rename from src/main/java/dev/failsafe/function/CheckedFunction.java rename to core/src/main/java/dev/failsafe/function/CheckedFunction.java diff --git a/src/main/java/dev/failsafe/function/CheckedPredicate.java b/core/src/main/java/dev/failsafe/function/CheckedPredicate.java similarity index 100% rename from src/main/java/dev/failsafe/function/CheckedPredicate.java rename to core/src/main/java/dev/failsafe/function/CheckedPredicate.java diff --git a/src/main/java/dev/failsafe/function/CheckedRunnable.java b/core/src/main/java/dev/failsafe/function/CheckedRunnable.java similarity index 100% rename from src/main/java/dev/failsafe/function/CheckedRunnable.java rename to core/src/main/java/dev/failsafe/function/CheckedRunnable.java diff --git a/src/main/java/dev/failsafe/function/CheckedSupplier.java b/core/src/main/java/dev/failsafe/function/CheckedSupplier.java similarity index 100% rename from src/main/java/dev/failsafe/function/CheckedSupplier.java rename to core/src/main/java/dev/failsafe/function/CheckedSupplier.java diff --git a/src/main/java/dev/failsafe/function/ContextualRunnable.java b/core/src/main/java/dev/failsafe/function/ContextualRunnable.java similarity index 100% rename from src/main/java/dev/failsafe/function/ContextualRunnable.java rename to core/src/main/java/dev/failsafe/function/ContextualRunnable.java diff --git a/src/main/java/dev/failsafe/function/ContextualSupplier.java b/core/src/main/java/dev/failsafe/function/ContextualSupplier.java similarity index 100% rename from src/main/java/dev/failsafe/function/ContextualSupplier.java rename to core/src/main/java/dev/failsafe/function/ContextualSupplier.java diff --git a/src/main/java/dev/failsafe/function/package-info.java b/core/src/main/java/dev/failsafe/function/package-info.java similarity index 100% rename from src/main/java/dev/failsafe/function/package-info.java rename to core/src/main/java/dev/failsafe/function/package-info.java diff --git a/src/main/java/dev/failsafe/internal/BulkheadExecutor.java b/core/src/main/java/dev/failsafe/internal/BulkheadExecutor.java similarity index 100% rename from src/main/java/dev/failsafe/internal/BulkheadExecutor.java rename to core/src/main/java/dev/failsafe/internal/BulkheadExecutor.java diff --git a/src/main/java/dev/failsafe/internal/BulkheadImpl.java b/core/src/main/java/dev/failsafe/internal/BulkheadImpl.java similarity index 100% rename from src/main/java/dev/failsafe/internal/BulkheadImpl.java rename to core/src/main/java/dev/failsafe/internal/BulkheadImpl.java diff --git a/src/main/java/dev/failsafe/internal/BurstyRateLimiterStats.java b/core/src/main/java/dev/failsafe/internal/BurstyRateLimiterStats.java similarity index 100% rename from src/main/java/dev/failsafe/internal/BurstyRateLimiterStats.java rename to core/src/main/java/dev/failsafe/internal/BurstyRateLimiterStats.java diff --git a/src/main/java/dev/failsafe/internal/CircuitBreakerExecutor.java b/core/src/main/java/dev/failsafe/internal/CircuitBreakerExecutor.java similarity index 100% rename from src/main/java/dev/failsafe/internal/CircuitBreakerExecutor.java rename to core/src/main/java/dev/failsafe/internal/CircuitBreakerExecutor.java diff --git a/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java b/core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java similarity index 100% rename from src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java rename to core/src/main/java/dev/failsafe/internal/CircuitBreakerImpl.java diff --git a/src/main/java/dev/failsafe/internal/CircuitState.java b/core/src/main/java/dev/failsafe/internal/CircuitState.java similarity index 100% rename from src/main/java/dev/failsafe/internal/CircuitState.java rename to core/src/main/java/dev/failsafe/internal/CircuitState.java diff --git a/src/main/java/dev/failsafe/internal/CircuitStats.java b/core/src/main/java/dev/failsafe/internal/CircuitStats.java similarity index 100% rename from src/main/java/dev/failsafe/internal/CircuitStats.java rename to core/src/main/java/dev/failsafe/internal/CircuitStats.java diff --git a/src/main/java/dev/failsafe/internal/ClosedState.java b/core/src/main/java/dev/failsafe/internal/ClosedState.java similarity index 100% rename from src/main/java/dev/failsafe/internal/ClosedState.java rename to core/src/main/java/dev/failsafe/internal/ClosedState.java diff --git a/src/main/java/dev/failsafe/internal/CountingCircuitStats.java b/core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java similarity index 100% rename from src/main/java/dev/failsafe/internal/CountingCircuitStats.java rename to core/src/main/java/dev/failsafe/internal/CountingCircuitStats.java diff --git a/src/main/java/dev/failsafe/internal/DefaultCircuitStats.java b/core/src/main/java/dev/failsafe/internal/DefaultCircuitStats.java similarity index 100% rename from src/main/java/dev/failsafe/internal/DefaultCircuitStats.java rename to core/src/main/java/dev/failsafe/internal/DefaultCircuitStats.java diff --git a/src/main/java/dev/failsafe/internal/EventHandler.java b/core/src/main/java/dev/failsafe/internal/EventHandler.java similarity index 100% rename from src/main/java/dev/failsafe/internal/EventHandler.java rename to core/src/main/java/dev/failsafe/internal/EventHandler.java diff --git a/src/main/java/dev/failsafe/internal/FallbackExecutor.java b/core/src/main/java/dev/failsafe/internal/FallbackExecutor.java similarity index 100% rename from src/main/java/dev/failsafe/internal/FallbackExecutor.java rename to core/src/main/java/dev/failsafe/internal/FallbackExecutor.java diff --git a/src/main/java/dev/failsafe/internal/FallbackImpl.java b/core/src/main/java/dev/failsafe/internal/FallbackImpl.java similarity index 100% rename from src/main/java/dev/failsafe/internal/FallbackImpl.java rename to core/src/main/java/dev/failsafe/internal/FallbackImpl.java diff --git a/src/main/java/dev/failsafe/internal/HalfOpenState.java b/core/src/main/java/dev/failsafe/internal/HalfOpenState.java similarity index 100% rename from src/main/java/dev/failsafe/internal/HalfOpenState.java rename to core/src/main/java/dev/failsafe/internal/HalfOpenState.java diff --git a/src/main/java/dev/failsafe/internal/OpenState.java b/core/src/main/java/dev/failsafe/internal/OpenState.java similarity index 100% rename from src/main/java/dev/failsafe/internal/OpenState.java rename to core/src/main/java/dev/failsafe/internal/OpenState.java diff --git a/src/main/java/dev/failsafe/internal/RateLimiterExecutor.java b/core/src/main/java/dev/failsafe/internal/RateLimiterExecutor.java similarity index 100% rename from src/main/java/dev/failsafe/internal/RateLimiterExecutor.java rename to core/src/main/java/dev/failsafe/internal/RateLimiterExecutor.java diff --git a/src/main/java/dev/failsafe/internal/RateLimiterImpl.java b/core/src/main/java/dev/failsafe/internal/RateLimiterImpl.java similarity index 100% rename from src/main/java/dev/failsafe/internal/RateLimiterImpl.java rename to core/src/main/java/dev/failsafe/internal/RateLimiterImpl.java diff --git a/src/main/java/dev/failsafe/internal/RateLimiterStats.java b/core/src/main/java/dev/failsafe/internal/RateLimiterStats.java similarity index 100% rename from src/main/java/dev/failsafe/internal/RateLimiterStats.java rename to core/src/main/java/dev/failsafe/internal/RateLimiterStats.java diff --git a/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java b/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java similarity index 99% rename from src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java rename to core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java index 7b7478a4..ec898187 100644 --- a/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java +++ b/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java @@ -96,6 +96,7 @@ public Function, ExecutionResult> apply( execution.setInterruptable(false); } + // Check again for cancellation if (execution.isCancelled(this)) return result; diff --git a/src/main/java/dev/failsafe/internal/RetryPolicyImpl.java b/core/src/main/java/dev/failsafe/internal/RetryPolicyImpl.java similarity index 100% rename from src/main/java/dev/failsafe/internal/RetryPolicyImpl.java rename to core/src/main/java/dev/failsafe/internal/RetryPolicyImpl.java diff --git a/src/main/java/dev/failsafe/internal/SmoothRateLimiterStats.java b/core/src/main/java/dev/failsafe/internal/SmoothRateLimiterStats.java similarity index 100% rename from src/main/java/dev/failsafe/internal/SmoothRateLimiterStats.java rename to core/src/main/java/dev/failsafe/internal/SmoothRateLimiterStats.java diff --git a/src/main/java/dev/failsafe/internal/TimedCircuitStats.java b/core/src/main/java/dev/failsafe/internal/TimedCircuitStats.java similarity index 100% rename from src/main/java/dev/failsafe/internal/TimedCircuitStats.java rename to core/src/main/java/dev/failsafe/internal/TimedCircuitStats.java diff --git a/src/main/java/dev/failsafe/internal/TimeoutExecutor.java b/core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java similarity index 100% rename from src/main/java/dev/failsafe/internal/TimeoutExecutor.java rename to core/src/main/java/dev/failsafe/internal/TimeoutExecutor.java diff --git a/src/main/java/dev/failsafe/internal/TimeoutImpl.java b/core/src/main/java/dev/failsafe/internal/TimeoutImpl.java similarity index 100% rename from src/main/java/dev/failsafe/internal/TimeoutImpl.java rename to core/src/main/java/dev/failsafe/internal/TimeoutImpl.java diff --git a/src/main/java/dev/failsafe/internal/util/Assert.java b/core/src/main/java/dev/failsafe/internal/util/Assert.java similarity index 100% rename from src/main/java/dev/failsafe/internal/util/Assert.java rename to core/src/main/java/dev/failsafe/internal/util/Assert.java diff --git a/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java b/core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java similarity index 100% rename from src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java rename to core/src/main/java/dev/failsafe/internal/util/DelegatingScheduler.java diff --git a/src/main/java/dev/failsafe/internal/util/Durations.java b/core/src/main/java/dev/failsafe/internal/util/Durations.java similarity index 100% rename from src/main/java/dev/failsafe/internal/util/Durations.java rename to core/src/main/java/dev/failsafe/internal/util/Durations.java diff --git a/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java b/core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java similarity index 100% rename from src/main/java/dev/failsafe/internal/util/FutureLinkedList.java rename to core/src/main/java/dev/failsafe/internal/util/FutureLinkedList.java diff --git a/src/main/java/dev/failsafe/internal/util/Lists.java b/core/src/main/java/dev/failsafe/internal/util/Lists.java similarity index 100% rename from src/main/java/dev/failsafe/internal/util/Lists.java rename to core/src/main/java/dev/failsafe/internal/util/Lists.java diff --git a/src/main/java/dev/failsafe/internal/util/Maths.java b/core/src/main/java/dev/failsafe/internal/util/Maths.java similarity index 100% rename from src/main/java/dev/failsafe/internal/util/Maths.java rename to core/src/main/java/dev/failsafe/internal/util/Maths.java diff --git a/src/main/java/dev/failsafe/internal/util/RandomDelay.java b/core/src/main/java/dev/failsafe/internal/util/RandomDelay.java similarity index 100% rename from src/main/java/dev/failsafe/internal/util/RandomDelay.java rename to core/src/main/java/dev/failsafe/internal/util/RandomDelay.java diff --git a/src/main/java/dev/failsafe/package-info.java b/core/src/main/java/dev/failsafe/package-info.java similarity index 100% rename from src/main/java/dev/failsafe/package-info.java rename to core/src/main/java/dev/failsafe/package-info.java diff --git a/src/main/java/dev/failsafe/spi/AsyncExecutionInternal.java b/core/src/main/java/dev/failsafe/spi/AsyncExecutionInternal.java similarity index 100% rename from src/main/java/dev/failsafe/spi/AsyncExecutionInternal.java rename to core/src/main/java/dev/failsafe/spi/AsyncExecutionInternal.java diff --git a/src/main/java/dev/failsafe/spi/DefaultScheduledFuture.java b/core/src/main/java/dev/failsafe/spi/DefaultScheduledFuture.java similarity index 100% rename from src/main/java/dev/failsafe/spi/DefaultScheduledFuture.java rename to core/src/main/java/dev/failsafe/spi/DefaultScheduledFuture.java diff --git a/src/main/java/dev/failsafe/spi/DelayablePolicy.java b/core/src/main/java/dev/failsafe/spi/DelayablePolicy.java similarity index 100% rename from src/main/java/dev/failsafe/spi/DelayablePolicy.java rename to core/src/main/java/dev/failsafe/spi/DelayablePolicy.java diff --git a/src/main/java/dev/failsafe/spi/ExecutionInternal.java b/core/src/main/java/dev/failsafe/spi/ExecutionInternal.java similarity index 86% rename from src/main/java/dev/failsafe/spi/ExecutionInternal.java rename to core/src/main/java/dev/failsafe/spi/ExecutionInternal.java index 02136e2a..d5317c5f 100644 --- a/src/main/java/dev/failsafe/spi/ExecutionInternal.java +++ b/core/src/main/java/dev/failsafe/spi/ExecutionInternal.java @@ -52,12 +52,14 @@ public interface ExecutionInternal extends ExecutionContext { void record(ExecutionResult result); /** - * Marks the execution as having been cancelled. + * Marks the execution as having been cancelled externally, which will cancel pending executions of all policies. */ void cancel(); /** - * Marks the execution as having been cancelled by the {@code policyExecutor}. + * Marks the execution as having been cancelled by the {@code policyExecutor}, which will also cancel pending + * executions of any inner policies of the {@code policyExecutor}. Outer policies of the {@code policyExecutor} will + * be unaffected. */ void cancel(PolicyExecutor policyExecutor); diff --git a/src/main/java/dev/failsafe/spi/ExecutionResult.java b/core/src/main/java/dev/failsafe/spi/ExecutionResult.java similarity index 100% rename from src/main/java/dev/failsafe/spi/ExecutionResult.java rename to core/src/main/java/dev/failsafe/spi/ExecutionResult.java diff --git a/src/main/java/dev/failsafe/spi/FailsafeFuture.java b/core/src/main/java/dev/failsafe/spi/FailsafeFuture.java similarity index 100% rename from src/main/java/dev/failsafe/spi/FailsafeFuture.java rename to core/src/main/java/dev/failsafe/spi/FailsafeFuture.java diff --git a/src/main/java/dev/failsafe/spi/FailurePolicy.java b/core/src/main/java/dev/failsafe/spi/FailurePolicy.java similarity index 100% rename from src/main/java/dev/failsafe/spi/FailurePolicy.java rename to core/src/main/java/dev/failsafe/spi/FailurePolicy.java diff --git a/src/main/java/dev/failsafe/spi/PolicyExecutor.java b/core/src/main/java/dev/failsafe/spi/PolicyExecutor.java similarity index 100% rename from src/main/java/dev/failsafe/spi/PolicyExecutor.java rename to core/src/main/java/dev/failsafe/spi/PolicyExecutor.java diff --git a/src/main/java/dev/failsafe/spi/Scheduler.java b/core/src/main/java/dev/failsafe/spi/Scheduler.java similarity index 100% rename from src/main/java/dev/failsafe/spi/Scheduler.java rename to core/src/main/java/dev/failsafe/spi/Scheduler.java diff --git a/src/main/java/dev/failsafe/spi/SyncExecutionInternal.java b/core/src/main/java/dev/failsafe/spi/SyncExecutionInternal.java similarity index 100% rename from src/main/java/dev/failsafe/spi/SyncExecutionInternal.java rename to core/src/main/java/dev/failsafe/spi/SyncExecutionInternal.java diff --git a/src/main/java/dev/failsafe/spi/package-info.java b/core/src/main/java/dev/failsafe/spi/package-info.java similarity index 100% rename from src/main/java/dev/failsafe/spi/package-info.java rename to core/src/main/java/dev/failsafe/spi/package-info.java diff --git a/src/main/javadoc/overview.html b/core/src/main/javadoc/overview.html similarity index 100% rename from src/main/javadoc/overview.html rename to core/src/main/javadoc/overview.html diff --git a/src/test/java/dev/failsafe/AsyncExecutionTest.java b/core/src/test/java/dev/failsafe/AsyncExecutionTest.java similarity index 100% rename from src/test/java/dev/failsafe/AsyncExecutionTest.java rename to core/src/test/java/dev/failsafe/AsyncExecutionTest.java diff --git a/src/test/java/dev/failsafe/AsyncFailsafeTest.java b/core/src/test/java/dev/failsafe/AsyncFailsafeTest.java similarity index 100% rename from src/test/java/dev/failsafe/AsyncFailsafeTest.java rename to core/src/test/java/dev/failsafe/AsyncFailsafeTest.java diff --git a/src/test/java/dev/failsafe/BulkheadBuilderTest.java b/core/src/test/java/dev/failsafe/BulkheadBuilderTest.java similarity index 100% rename from src/test/java/dev/failsafe/BulkheadBuilderTest.java rename to core/src/test/java/dev/failsafe/BulkheadBuilderTest.java diff --git a/src/test/java/dev/failsafe/CircuitBreakerBuilderTest.java b/core/src/test/java/dev/failsafe/CircuitBreakerBuilderTest.java similarity index 100% rename from src/test/java/dev/failsafe/CircuitBreakerBuilderTest.java rename to core/src/test/java/dev/failsafe/CircuitBreakerBuilderTest.java diff --git a/src/test/java/dev/failsafe/CircuitBreakerTest.java b/core/src/test/java/dev/failsafe/CircuitBreakerTest.java similarity index 100% rename from src/test/java/dev/failsafe/CircuitBreakerTest.java rename to core/src/test/java/dev/failsafe/CircuitBreakerTest.java diff --git a/src/test/java/dev/failsafe/DelayablePolicyTest.java b/core/src/test/java/dev/failsafe/DelayablePolicyTest.java similarity index 100% rename from src/test/java/dev/failsafe/DelayablePolicyTest.java rename to core/src/test/java/dev/failsafe/DelayablePolicyTest.java diff --git a/src/test/java/dev/failsafe/ExecutionTest.java b/core/src/test/java/dev/failsafe/ExecutionTest.java similarity index 100% rename from src/test/java/dev/failsafe/ExecutionTest.java rename to core/src/test/java/dev/failsafe/ExecutionTest.java diff --git a/src/test/java/dev/failsafe/FailsafeFutureTest.java b/core/src/test/java/dev/failsafe/FailsafeFutureTest.java similarity index 100% rename from src/test/java/dev/failsafe/FailsafeFutureTest.java rename to core/src/test/java/dev/failsafe/FailsafeFutureTest.java diff --git a/src/test/java/dev/failsafe/FailsafeTest.java b/core/src/test/java/dev/failsafe/FailsafeTest.java similarity index 100% rename from src/test/java/dev/failsafe/FailsafeTest.java rename to core/src/test/java/dev/failsafe/FailsafeTest.java diff --git a/src/test/java/dev/failsafe/FailurePolicyBuilderTest.java b/core/src/test/java/dev/failsafe/FailurePolicyBuilderTest.java similarity index 100% rename from src/test/java/dev/failsafe/FailurePolicyBuilderTest.java rename to core/src/test/java/dev/failsafe/FailurePolicyBuilderTest.java diff --git a/src/test/java/dev/failsafe/FailurePolicyTest.java b/core/src/test/java/dev/failsafe/FailurePolicyTest.java similarity index 100% rename from src/test/java/dev/failsafe/FailurePolicyTest.java rename to core/src/test/java/dev/failsafe/FailurePolicyTest.java diff --git a/src/test/java/dev/failsafe/FallbackBuilderTest.java b/core/src/test/java/dev/failsafe/FallbackBuilderTest.java similarity index 100% rename from src/test/java/dev/failsafe/FallbackBuilderTest.java rename to core/src/test/java/dev/failsafe/FallbackBuilderTest.java diff --git a/src/test/java/dev/failsafe/ListenersTest.java b/core/src/test/java/dev/failsafe/ListenersTest.java similarity index 100% rename from src/test/java/dev/failsafe/ListenersTest.java rename to core/src/test/java/dev/failsafe/ListenersTest.java diff --git a/src/test/java/dev/failsafe/RateLimiterBuilderTest.java b/core/src/test/java/dev/failsafe/RateLimiterBuilderTest.java similarity index 100% rename from src/test/java/dev/failsafe/RateLimiterBuilderTest.java rename to core/src/test/java/dev/failsafe/RateLimiterBuilderTest.java diff --git a/src/test/java/dev/failsafe/RetryPolicyBuilderTest.java b/core/src/test/java/dev/failsafe/RetryPolicyBuilderTest.java similarity index 100% rename from src/test/java/dev/failsafe/RetryPolicyBuilderTest.java rename to core/src/test/java/dev/failsafe/RetryPolicyBuilderTest.java diff --git a/src/test/java/dev/failsafe/TimeoutBuilderTest.java b/core/src/test/java/dev/failsafe/TimeoutBuilderTest.java similarity index 100% rename from src/test/java/dev/failsafe/TimeoutBuilderTest.java rename to core/src/test/java/dev/failsafe/TimeoutBuilderTest.java diff --git a/src/test/java/dev/failsafe/functional/BlockedExecutionTest.java b/core/src/test/java/dev/failsafe/functional/BlockedExecutionTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/BlockedExecutionTest.java rename to core/src/test/java/dev/failsafe/functional/BlockedExecutionTest.java diff --git a/src/test/java/dev/failsafe/functional/BulkheadTest.java b/core/src/test/java/dev/failsafe/functional/BulkheadTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/BulkheadTest.java rename to core/src/test/java/dev/failsafe/functional/BulkheadTest.java diff --git a/src/test/java/dev/failsafe/functional/CircuitBreakerTest.java b/core/src/test/java/dev/failsafe/functional/CircuitBreakerTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/CircuitBreakerTest.java rename to core/src/test/java/dev/failsafe/functional/CircuitBreakerTest.java diff --git a/src/test/java/dev/failsafe/functional/DelayableCircuitBreakerTest.java b/core/src/test/java/dev/failsafe/functional/DelayableCircuitBreakerTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/DelayableCircuitBreakerTest.java rename to core/src/test/java/dev/failsafe/functional/DelayableCircuitBreakerTest.java diff --git a/src/test/java/dev/failsafe/functional/DelayableRetryPolicyTest.java b/core/src/test/java/dev/failsafe/functional/DelayableRetryPolicyTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/DelayableRetryPolicyTest.java rename to core/src/test/java/dev/failsafe/functional/DelayableRetryPolicyTest.java diff --git a/src/test/java/dev/failsafe/functional/ExecutorConfigurationTest.java b/core/src/test/java/dev/failsafe/functional/ExecutorConfigurationTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/ExecutorConfigurationTest.java rename to core/src/test/java/dev/failsafe/functional/ExecutorConfigurationTest.java diff --git a/src/test/java/dev/failsafe/functional/ExecutorTest.java b/core/src/test/java/dev/failsafe/functional/ExecutorTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/ExecutorTest.java rename to core/src/test/java/dev/failsafe/functional/ExecutorTest.java diff --git a/src/test/java/dev/failsafe/functional/FailsafeFutureCancellationTest.java b/core/src/test/java/dev/failsafe/functional/FailsafeFutureCancellationTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/FailsafeFutureCancellationTest.java rename to core/src/test/java/dev/failsafe/functional/FailsafeFutureCancellationTest.java diff --git a/src/test/java/dev/failsafe/functional/FailsafeFutureCompletionTest.java b/core/src/test/java/dev/failsafe/functional/FailsafeFutureCompletionTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/FailsafeFutureCompletionTest.java rename to core/src/test/java/dev/failsafe/functional/FailsafeFutureCompletionTest.java diff --git a/src/test/java/dev/failsafe/functional/FallbackTest.java b/core/src/test/java/dev/failsafe/functional/FallbackTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/FallbackTest.java rename to core/src/test/java/dev/failsafe/functional/FallbackTest.java diff --git a/src/test/java/dev/failsafe/functional/InterruptionTest.java b/core/src/test/java/dev/failsafe/functional/InterruptionTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/InterruptionTest.java rename to core/src/test/java/dev/failsafe/functional/InterruptionTest.java diff --git a/src/test/java/dev/failsafe/functional/NestedCircuitBreakerTest.java b/core/src/test/java/dev/failsafe/functional/NestedCircuitBreakerTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/NestedCircuitBreakerTest.java rename to core/src/test/java/dev/failsafe/functional/NestedCircuitBreakerTest.java diff --git a/src/test/java/dev/failsafe/functional/NestedRetryPolicyTest.java b/core/src/test/java/dev/failsafe/functional/NestedRetryPolicyTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/NestedRetryPolicyTest.java rename to core/src/test/java/dev/failsafe/functional/NestedRetryPolicyTest.java diff --git a/src/test/java/dev/failsafe/functional/NestedTimeoutTest.java b/core/src/test/java/dev/failsafe/functional/NestedTimeoutTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/NestedTimeoutTest.java rename to core/src/test/java/dev/failsafe/functional/NestedTimeoutTest.java diff --git a/src/test/java/dev/failsafe/functional/NoPolicyTest.java b/core/src/test/java/dev/failsafe/functional/NoPolicyTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/NoPolicyTest.java rename to core/src/test/java/dev/failsafe/functional/NoPolicyTest.java diff --git a/src/test/java/dev/failsafe/functional/PolicyCompositionExecutionTest.java b/core/src/test/java/dev/failsafe/functional/PolicyCompositionExecutionTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/PolicyCompositionExecutionTest.java rename to core/src/test/java/dev/failsafe/functional/PolicyCompositionExecutionTest.java diff --git a/src/test/java/dev/failsafe/functional/PolicyCompositionTest.java b/core/src/test/java/dev/failsafe/functional/PolicyCompositionTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/PolicyCompositionTest.java rename to core/src/test/java/dev/failsafe/functional/PolicyCompositionTest.java diff --git a/src/test/java/dev/failsafe/functional/RateLimiterTest.java b/core/src/test/java/dev/failsafe/functional/RateLimiterTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/RateLimiterTest.java rename to core/src/test/java/dev/failsafe/functional/RateLimiterTest.java diff --git a/src/test/java/dev/failsafe/functional/RetryPolicyTest.java b/core/src/test/java/dev/failsafe/functional/RetryPolicyTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/RetryPolicyTest.java rename to core/src/test/java/dev/failsafe/functional/RetryPolicyTest.java diff --git a/src/test/java/dev/failsafe/functional/ShutdownExecutorTest.java b/core/src/test/java/dev/failsafe/functional/ShutdownExecutorTest.java similarity index 100% rename from src/test/java/dev/failsafe/functional/ShutdownExecutorTest.java rename to core/src/test/java/dev/failsafe/functional/ShutdownExecutorTest.java diff --git a/src/test/java/dev/failsafe/functional/TimeoutTest.java b/core/src/test/java/dev/failsafe/functional/TimeoutTest.java similarity index 99% rename from src/test/java/dev/failsafe/functional/TimeoutTest.java rename to core/src/test/java/dev/failsafe/functional/TimeoutTest.java index 3fc5b06e..334d6aa2 100644 --- a/src/test/java/dev/failsafe/functional/TimeoutTest.java +++ b/core/src/test/java/dev/failsafe/functional/TimeoutTest.java @@ -206,7 +206,7 @@ public void testFallbackTimeoutWithBlockedSupplier() { fbStats.reset(); }, Failsafe.with(fallback).compose(timeout), ctx -> { System.out.println("Executing"); - Thread.sleep(200); + Thread.sleep(100); throw new Exception(); }, (f, e) -> { assertEquals(e.getAttemptCount(), 1); @@ -216,11 +216,11 @@ public void testFallbackTimeoutWithBlockedSupplier() { }, IllegalStateException.class); // Test without interrupt - Timeout timeout = withStatsAndLogs(Timeout.builder(Duration.ofMillis(100)), timeoutStats).build(); + Timeout timeout = withStatsAndLogs(Timeout.builder(Duration.ofMillis(1)), timeoutStats).build(); test.accept(timeout); // Test with interrupt - timeout = withStatsAndLogs(Timeout.builder(Duration.ofMillis(100)).withInterrupt(), timeoutStats).build(); + timeout = withStatsAndLogs(Timeout.builder(Duration.ofMillis(1)).withInterrupt(), timeoutStats).build(); test.accept(timeout); } diff --git a/src/test/java/dev/failsafe/functional/package-info.java b/core/src/test/java/dev/failsafe/functional/package-info.java similarity index 100% rename from src/test/java/dev/failsafe/functional/package-info.java rename to core/src/test/java/dev/failsafe/functional/package-info.java diff --git a/src/test/java/dev/failsafe/internal/BurstyRateLimiterStatsTest.java b/core/src/test/java/dev/failsafe/internal/BurstyRateLimiterStatsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/BurstyRateLimiterStatsTest.java rename to core/src/test/java/dev/failsafe/internal/BurstyRateLimiterStatsTest.java diff --git a/src/test/java/dev/failsafe/internal/CircuitStatsTest.java b/core/src/test/java/dev/failsafe/internal/CircuitStatsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/CircuitStatsTest.java rename to core/src/test/java/dev/failsafe/internal/CircuitStatsTest.java diff --git a/src/test/java/dev/failsafe/internal/ClosedStateTest.java b/core/src/test/java/dev/failsafe/internal/ClosedStateTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/ClosedStateTest.java rename to core/src/test/java/dev/failsafe/internal/ClosedStateTest.java diff --git a/src/test/java/dev/failsafe/internal/CountingCircuitStatsTest.java b/core/src/test/java/dev/failsafe/internal/CountingCircuitStatsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/CountingCircuitStatsTest.java rename to core/src/test/java/dev/failsafe/internal/CountingCircuitStatsTest.java diff --git a/src/test/java/dev/failsafe/internal/HalfOpenStateTest.java b/core/src/test/java/dev/failsafe/internal/HalfOpenStateTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/HalfOpenStateTest.java rename to core/src/test/java/dev/failsafe/internal/HalfOpenStateTest.java diff --git a/src/test/java/dev/failsafe/internal/InternalTesting.java b/core/src/test/java/dev/failsafe/internal/InternalTesting.java similarity index 100% rename from src/test/java/dev/failsafe/internal/InternalTesting.java rename to core/src/test/java/dev/failsafe/internal/InternalTesting.java diff --git a/src/test/java/dev/failsafe/internal/OpenStateTest.java b/core/src/test/java/dev/failsafe/internal/OpenStateTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/OpenStateTest.java rename to core/src/test/java/dev/failsafe/internal/OpenStateTest.java diff --git a/src/test/java/dev/failsafe/internal/RateLimiterImplTest.java b/core/src/test/java/dev/failsafe/internal/RateLimiterImplTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/RateLimiterImplTest.java rename to core/src/test/java/dev/failsafe/internal/RateLimiterImplTest.java diff --git a/src/test/java/dev/failsafe/internal/RateLimiterStatsTest.java b/core/src/test/java/dev/failsafe/internal/RateLimiterStatsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/RateLimiterStatsTest.java rename to core/src/test/java/dev/failsafe/internal/RateLimiterStatsTest.java diff --git a/src/test/java/dev/failsafe/internal/RetryPolicyImplTest.java b/core/src/test/java/dev/failsafe/internal/RetryPolicyImplTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/RetryPolicyImplTest.java rename to core/src/test/java/dev/failsafe/internal/RetryPolicyImplTest.java diff --git a/src/test/java/dev/failsafe/internal/SmoothRateLimiterStatsTest.java b/core/src/test/java/dev/failsafe/internal/SmoothRateLimiterStatsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/SmoothRateLimiterStatsTest.java rename to core/src/test/java/dev/failsafe/internal/SmoothRateLimiterStatsTest.java diff --git a/src/test/java/dev/failsafe/internal/TimedCircuitStatsTest.java b/core/src/test/java/dev/failsafe/internal/TimedCircuitStatsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/TimedCircuitStatsTest.java rename to core/src/test/java/dev/failsafe/internal/TimedCircuitStatsTest.java diff --git a/src/test/java/dev/failsafe/internal/util/DelegatingSchedulerTest.java b/core/src/test/java/dev/failsafe/internal/util/DelegatingSchedulerTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/util/DelegatingSchedulerTest.java rename to core/src/test/java/dev/failsafe/internal/util/DelegatingSchedulerTest.java diff --git a/src/test/java/dev/failsafe/internal/util/DurationsTest.java b/core/src/test/java/dev/failsafe/internal/util/DurationsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/util/DurationsTest.java rename to core/src/test/java/dev/failsafe/internal/util/DurationsTest.java diff --git a/src/test/java/dev/failsafe/internal/util/FutureLinkedListTest.java b/core/src/test/java/dev/failsafe/internal/util/FutureLinkedListTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/util/FutureLinkedListTest.java rename to core/src/test/java/dev/failsafe/internal/util/FutureLinkedListTest.java diff --git a/src/test/java/dev/failsafe/internal/util/ListsTest.java b/core/src/test/java/dev/failsafe/internal/util/ListsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/util/ListsTest.java rename to core/src/test/java/dev/failsafe/internal/util/ListsTest.java diff --git a/src/test/java/dev/failsafe/internal/util/MathsTest.java b/core/src/test/java/dev/failsafe/internal/util/MathsTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/util/MathsTest.java rename to core/src/test/java/dev/failsafe/internal/util/MathsTest.java diff --git a/src/test/java/dev/failsafe/internal/util/RandomDelayTest.java b/core/src/test/java/dev/failsafe/internal/util/RandomDelayTest.java similarity index 100% rename from src/test/java/dev/failsafe/internal/util/RandomDelayTest.java rename to core/src/test/java/dev/failsafe/internal/util/RandomDelayTest.java diff --git a/src/test/java/dev/failsafe/issues/Issue115Test.java b/core/src/test/java/dev/failsafe/issues/Issue115Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue115Test.java rename to core/src/test/java/dev/failsafe/issues/Issue115Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue131Test.java b/core/src/test/java/dev/failsafe/issues/Issue131Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue131Test.java rename to core/src/test/java/dev/failsafe/issues/Issue131Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue146Test.java b/core/src/test/java/dev/failsafe/issues/Issue146Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue146Test.java rename to core/src/test/java/dev/failsafe/issues/Issue146Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue165Test.java b/core/src/test/java/dev/failsafe/issues/Issue165Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue165Test.java rename to core/src/test/java/dev/failsafe/issues/Issue165Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue177Test.java b/core/src/test/java/dev/failsafe/issues/Issue177Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue177Test.java rename to core/src/test/java/dev/failsafe/issues/Issue177Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue190Test.java b/core/src/test/java/dev/failsafe/issues/Issue190Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue190Test.java rename to core/src/test/java/dev/failsafe/issues/Issue190Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue192Test.java b/core/src/test/java/dev/failsafe/issues/Issue192Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue192Test.java rename to core/src/test/java/dev/failsafe/issues/Issue192Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue206Test.java b/core/src/test/java/dev/failsafe/issues/Issue206Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue206Test.java rename to core/src/test/java/dev/failsafe/issues/Issue206Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue215Test.java b/core/src/test/java/dev/failsafe/issues/Issue215Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue215Test.java rename to core/src/test/java/dev/failsafe/issues/Issue215Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue218Test.java b/core/src/test/java/dev/failsafe/issues/Issue218Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue218Test.java rename to core/src/test/java/dev/failsafe/issues/Issue218Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue224Test.java b/core/src/test/java/dev/failsafe/issues/Issue224Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue224Test.java rename to core/src/test/java/dev/failsafe/issues/Issue224Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue231Test.java b/core/src/test/java/dev/failsafe/issues/Issue231Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue231Test.java rename to core/src/test/java/dev/failsafe/issues/Issue231Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue240Test.java b/core/src/test/java/dev/failsafe/issues/Issue240Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue240Test.java rename to core/src/test/java/dev/failsafe/issues/Issue240Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue242Test.java b/core/src/test/java/dev/failsafe/issues/Issue242Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue242Test.java rename to core/src/test/java/dev/failsafe/issues/Issue242Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue260Test.java b/core/src/test/java/dev/failsafe/issues/Issue260Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue260Test.java rename to core/src/test/java/dev/failsafe/issues/Issue260Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue267Test.java b/core/src/test/java/dev/failsafe/issues/Issue267Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue267Test.java rename to core/src/test/java/dev/failsafe/issues/Issue267Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue284Test.java b/core/src/test/java/dev/failsafe/issues/Issue284Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue284Test.java rename to core/src/test/java/dev/failsafe/issues/Issue284Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue298Test.java b/core/src/test/java/dev/failsafe/issues/Issue298Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue298Test.java rename to core/src/test/java/dev/failsafe/issues/Issue298Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue311Test.java b/core/src/test/java/dev/failsafe/issues/Issue311Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue311Test.java rename to core/src/test/java/dev/failsafe/issues/Issue311Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue36Test.java b/core/src/test/java/dev/failsafe/issues/Issue36Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue36Test.java rename to core/src/test/java/dev/failsafe/issues/Issue36Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue52Test.java b/core/src/test/java/dev/failsafe/issues/Issue52Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue52Test.java rename to core/src/test/java/dev/failsafe/issues/Issue52Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue55Test.java b/core/src/test/java/dev/failsafe/issues/Issue55Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue55Test.java rename to core/src/test/java/dev/failsafe/issues/Issue55Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue5Test.java b/core/src/test/java/dev/failsafe/issues/Issue5Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue5Test.java rename to core/src/test/java/dev/failsafe/issues/Issue5Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue75Test.java b/core/src/test/java/dev/failsafe/issues/Issue75Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue75Test.java rename to core/src/test/java/dev/failsafe/issues/Issue75Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue76Test.java b/core/src/test/java/dev/failsafe/issues/Issue76Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue76Test.java rename to core/src/test/java/dev/failsafe/issues/Issue76Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue84Test.java b/core/src/test/java/dev/failsafe/issues/Issue84Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue84Test.java rename to core/src/test/java/dev/failsafe/issues/Issue84Test.java diff --git a/src/test/java/dev/failsafe/issues/Issue9Test.java b/core/src/test/java/dev/failsafe/issues/Issue9Test.java similarity index 100% rename from src/test/java/dev/failsafe/issues/Issue9Test.java rename to core/src/test/java/dev/failsafe/issues/Issue9Test.java diff --git a/src/test/java/dev/failsafe/testing/Asserts.java b/core/src/test/java/dev/failsafe/testing/Asserts.java similarity index 100% rename from src/test/java/dev/failsafe/testing/Asserts.java rename to core/src/test/java/dev/failsafe/testing/Asserts.java diff --git a/src/test/java/dev/failsafe/testing/Logging.java b/core/src/test/java/dev/failsafe/testing/Logging.java similarity index 100% rename from src/test/java/dev/failsafe/testing/Logging.java rename to core/src/test/java/dev/failsafe/testing/Logging.java diff --git a/src/test/java/dev/failsafe/testing/Mocking.java b/core/src/test/java/dev/failsafe/testing/Mocking.java similarity index 100% rename from src/test/java/dev/failsafe/testing/Mocking.java rename to core/src/test/java/dev/failsafe/testing/Mocking.java diff --git a/src/test/java/dev/failsafe/testing/TestCaseLogger.java b/core/src/test/java/dev/failsafe/testing/TestCaseLogger.java similarity index 100% rename from src/test/java/dev/failsafe/testing/TestCaseLogger.java rename to core/src/test/java/dev/failsafe/testing/TestCaseLogger.java diff --git a/src/test/java/dev/failsafe/testing/Testing.java b/core/src/test/java/dev/failsafe/testing/Testing.java similarity index 100% rename from src/test/java/dev/failsafe/testing/Testing.java rename to core/src/test/java/dev/failsafe/testing/Testing.java diff --git a/src/test/java/dev/failsafe/testing/package-info.java b/core/src/test/java/dev/failsafe/testing/package-info.java similarity index 100% rename from src/test/java/dev/failsafe/testing/package-info.java rename to core/src/test/java/dev/failsafe/testing/package-info.java diff --git a/examples/pom.xml b/examples/pom.xml new file mode 100644 index 00000000..d8ecde24 --- /dev/null +++ b/examples/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + dev.failsafe + failsafe-parent + 3.2.2-SNAPSHOT + + + failsafe-examples + Failsafe Examples + + + + ${project.groupId} + failsafe + ${project.version} + + + + + io.reactivex + rxjava + 1.0.12 + + + io.netty + netty-all + 4.1.51.Final + + + io.vertx + vertx-core + 3.9.8 + + + + + org.testng + testng + 6.9.10 + + + org.mockito + mockito-core + 4.2.0 + + + diff --git a/src/test/java/dev/failsafe/examples/AsyncExample.java b/examples/src/main/java/dev/failsafe/examples/AsyncExample.java similarity index 100% rename from src/test/java/dev/failsafe/examples/AsyncExample.java rename to examples/src/main/java/dev/failsafe/examples/AsyncExample.java diff --git a/src/test/java/dev/failsafe/examples/Java8Example.java b/examples/src/main/java/dev/failsafe/examples/Java8Example.java similarity index 100% rename from src/test/java/dev/failsafe/examples/Java8Example.java rename to examples/src/main/java/dev/failsafe/examples/Java8Example.java diff --git a/src/test/java/dev/failsafe/examples/NettyExample.java b/examples/src/main/java/dev/failsafe/examples/NettyExample.java similarity index 100% rename from src/test/java/dev/failsafe/examples/NettyExample.java rename to examples/src/main/java/dev/failsafe/examples/NettyExample.java diff --git a/src/test/java/dev/failsafe/examples/RetryLoopExample.java b/examples/src/main/java/dev/failsafe/examples/RetryLoopExample.java similarity index 100% rename from src/test/java/dev/failsafe/examples/RetryLoopExample.java rename to examples/src/main/java/dev/failsafe/examples/RetryLoopExample.java diff --git a/src/test/java/dev/failsafe/examples/RxJavaExample.java b/examples/src/main/java/dev/failsafe/examples/RxJavaExample.java similarity index 100% rename from src/test/java/dev/failsafe/examples/RxJavaExample.java rename to examples/src/main/java/dev/failsafe/examples/RxJavaExample.java diff --git a/src/test/java/dev/failsafe/examples/VertxExample.java b/examples/src/main/java/dev/failsafe/examples/VertxExample.java similarity index 100% rename from src/test/java/dev/failsafe/examples/VertxExample.java rename to examples/src/main/java/dev/failsafe/examples/VertxExample.java diff --git a/modules/okhttp/pom.xml b/modules/okhttp/pom.xml new file mode 100644 index 00000000..f7c8dbfe --- /dev/null +++ b/modules/okhttp/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + + dev.failsafe + failsafe-parent + 3.2.2-SNAPSHOT + ../../pom.xml + + + failsafe-okhttp + Failsafe OkHttp + + + + ${project.groupId} + failsafe + ${project.version} + + + com.squareup.okhttp3 + okhttp + 4.9.3 + + + + + ${project.groupId} + failsafe + ${project.version} + test-jar + test + + + com.github.tomakehurst + wiremock-jre8 + 2.32.0 + test + + + diff --git a/modules/okhttp/src/main/java/dev/failsafe/okhttp/FailsafeCall.java b/modules/okhttp/src/main/java/dev/failsafe/okhttp/FailsafeCall.java new file mode 100644 index 00000000..8424ac72 --- /dev/null +++ b/modules/okhttp/src/main/java/dev/failsafe/okhttp/FailsafeCall.java @@ -0,0 +1,170 @@ +/* + * Copyright 2022 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.okhttp; + +import dev.failsafe.*; +import dev.failsafe.internal.util.Assert; +import okhttp3.Callback; +import okhttp3.Response; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * A Failsafe wrapped OkHttp {@link Call}. Supports synchronous and asynchronous executions, and cancellation. + * + * @author Jonathan Halterman + */ +public final class FailsafeCall { + private final FailsafeExecutor failsafe; + private final okhttp3.Call initialCall; + + private volatile Call failsafeCall; + private volatile CompletableFuture failsafeFuture; + private AtomicBoolean cancelled = new AtomicBoolean(); + private AtomicBoolean executed = new AtomicBoolean(); + + private FailsafeCall(okhttp3.Call call, FailsafeExecutor failsafe) { + this.initialCall = call; + this.failsafe = failsafe; + } + + /** + * Returns a FailsafeCall for the {@code call}, {@code outerPolicy} and {@code policies}. See {@link + * Failsafe#with(Policy, Policy[])} for docs on how policy composition works. + * + * @param

policy type + * @throws NullPointerException if {@code call} or {@code outerPolicy} are null + */ + @SafeVarargs + public static

> FailsafeCall of(okhttp3.Call call, P outerPolicy, P... policies) { + return of(call, Failsafe.with(outerPolicy, policies)); + } + + /** + * Returns a FailsafeCall for the {@code call} and {@code failsafeExecutor}. + * + * @throws NullPointerException if {@code call} or {@code failsafeExecutor} are null + */ + public static FailsafeCall of(okhttp3.Call call, FailsafeExecutor failsafeExecutor) { + return new FailsafeCall(Assert.notNull(call, "call"), Assert.notNull(failsafeExecutor, "failsafeExecutor")); + } + + /** + * Cancels the call. + */ + public void cancel() { + if (!cancelled.compareAndSet(false, true)) + return; + if (failsafeCall != null) + failsafeCall.cancel(); + if (failsafeFuture != null) + failsafeFuture.cancel(false); + } + + /** + * Returns a clone of the FailsafeCall. + */ + public FailsafeCall clone() { + return FailsafeCall.of(initialCall.clone(), failsafe); + } + + /** + * Executes the call until a successful response is returned or the configured policies are exceeded. To avoid leaking + * resources callers should {@link Response#close() close} the Response which in turn will close the underlying + * ResponseBody. + * + * @throws IllegalStateException if the call has already been executed + * @throws IOException if the request could not be executed due to cancellation, a connectivity problem, or timeout + * @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can + * be used to learn the underlying checked exception. + */ + public Response execute() throws IOException { + Assert.isTrue(executed.compareAndSet(false, true), "already executed"); + + failsafeCall = failsafe.getCall(ctx -> { + return prepareCall(ctx).execute(); + }); + + try { + return failsafeCall.execute(); + } catch (FailsafeException e) { + if (e.getCause() instanceof IOException) + throw (IOException) e.getCause(); + throw e; + } + } + + /** + * Executes the call asynchronously until a successful result is returned or the configured policies are exceeded. To + * avoid leaking resources callers should {@link Response#close() close} the Response which in turn will close the + * underlying ResponseBody. + */ + public CompletableFuture executeAsync() { + if (!executed.compareAndSet(false, true)) { + CompletableFuture result = new CompletableFuture<>(); + result.completeExceptionally(new IllegalStateException("already executed")); + return result; + } + + failsafeFuture = failsafe.getAsyncExecution(exec -> { + prepareCall(exec).enqueue(new Callback() { + @Override + public void onResponse(okhttp3.Call call, Response response) { + exec.recordResult(response); + } + + @Override + public void onFailure(okhttp3.Call call, IOException e) { + exec.recordException(e); + } + }); + }); + + return failsafeFuture; + } + + /** + * Returns whether the call has been cancelled. + */ + public boolean isCanceled() { + return cancelled.get(); + } + + /** + * Returns whether the call has been executed. + */ + public boolean isExecuted() { + return executed.get(); + } + + private okhttp3.Call prepareCall(ExecutionContext ctx) { + okhttp3.Call call; + if (ctx.isFirstAttempt()) { + call = initialCall; + } else { + Response response = ctx.getLastResult(); + if (response != null) + response.close(); + call = initialCall.clone(); + } + + // Propagate cancellation to the call + ctx.onCancel(call::cancel); + return call; + } +} diff --git a/modules/okhttp/src/test/java/dev/failsafe/okhttp/FailsafeCallTest.java b/modules/okhttp/src/test/java/dev/failsafe/okhttp/FailsafeCallTest.java new file mode 100644 index 00000000..c9c15c37 --- /dev/null +++ b/modules/okhttp/src/test/java/dev/failsafe/okhttp/FailsafeCallTest.java @@ -0,0 +1,209 @@ +/* + * Copyright 2022 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.okhttp; + +import com.github.tomakehurst.wiremock.WireMockServer; +import dev.failsafe.*; +import dev.failsafe.okhttp.testing.OkHttpTesting; +import okhttp3.Call; +import okhttp3.*; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.time.Duration; +import java.util.concurrent.CancellationException; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +@Test +public class FailsafeCallTest extends OkHttpTesting { + public static final String URL = "http://localhost:8080"; + + WireMockServer server; + OkHttpClient client = new OkHttpClient.Builder().build(); + + @BeforeMethod + protected void beforeMethod() { + server = new WireMockServer(); + server.start(); + } + + @AfterMethod + protected void afterMethod() { + server.stop(); + } + + public void testSuccess() { + // Given + mockResponse(200, "foo"); + FailsafeExecutor failsafe = Failsafe.with(RetryPolicy.ofDefaults()); + Call call = callFor("/test"); + + // When / Then + testRequest(failsafe, call, (f, e) -> { + assertEquals(e.getAttemptCount(), 1); + assertEquals(e.getExecutionCount(), 1); + }, 200, "foo"); + assertCalled("/test", 2); + } + + public void testRetryPolicyOn400() { + // Given + mockResponse(400, "foo"); + RetryPolicy retryPolicy = RetryPolicy.builder().handleResultIf(r -> r.code() == 400).build(); + FailsafeExecutor failsafe = Failsafe.with(retryPolicy); + Call call = callFor("/test"); + + // When / Then + testRequest(failsafe, call, (f, e) -> { + assertEquals(e.getAttemptCount(), 3); + assertEquals(e.getExecutionCount(), 3); + }, 400, "foo"); + assertCalled("/test", 6); + } + + public void testRetryPolicyOnResult() { + // Given + mockResponse(200, "bad"); + RetryPolicy retryPolicy = RetryPolicy.builder() + .handleResultIf(r -> "bad".equals(r.peekBody(Long.MAX_VALUE).string())) + .build(); + FailsafeExecutor failsafe = Failsafe.with(retryPolicy); + Call call = callFor("/test"); + + // When / Then + testRequest(failsafe, call, (f, e) -> { + assertEquals(e.getAttemptCount(), 3); + assertEquals(e.getExecutionCount(), 3); + }, 200, "bad"); + assertCalled("/test", 6); + } + + public void testRetryPolicyFallback() { + // Given + mockResponse(400, "foo"); + Fallback fallback = Fallback.builder(r -> { + Response response = r.getLastResult(); + ResponseBody body = ResponseBody.create("fallback", response.body().contentType()); + return response.newBuilder().code(200).body(body).build(); + }).handleResultIf(r -> r.code() == 400).build(); + RetryPolicy retryPolicy = RetryPolicy.builder().handleResultIf(r -> r.code() == 400).build(); + FailsafeExecutor failsafe = Failsafe.with(fallback, retryPolicy); + Call call = callFor("/test"); + + // When / Then + testRequest(failsafe, call, (f, e) -> { + assertEquals(e.getAttemptCount(), 3); + assertEquals(e.getExecutionCount(), 3); + }, 200, "fallback"); + assertCalled("/test", 6); + } + + /** + * Asserts that an open circuit breaker prevents executions from occurring, even with outer retries. + */ + public void testCircuitBreaker() { + // Given + mockResponse(200, "foo"); + CircuitBreaker breaker = CircuitBreaker.ofDefaults(); + FailsafeExecutor failsafe = Failsafe.with(RetryPolicy.ofDefaults(), breaker); + Call call = callFor("/test"); + breaker.open(); + + // When / Then + testFailure(failsafe, call, (f, e) -> { + assertEquals(e.getAttemptCount(), 3); + assertEquals(e.getExecutionCount(), 0); + }, CircuitBreakerOpenException.class); + assertCalled("/test", 0); + } + + public void testTimeout() { + // Given + mockDelayedResponse(200, "foo", 1000); + FailsafeExecutor failsafe = Failsafe.with(Timeout.of(Duration.ofMillis(100))); + Call call = callFor("/test"); + + // When / Then + testFailure(failsafe, call, (f, e) -> { + assertEquals(e.getAttemptCount(), 1); + assertEquals(e.getExecutionCount(), 1); + }, TimeoutExceededException.class); + assertCalled("/test", 2); + } + + public void testIOException() { + server.stop(); + FailsafeExecutor failsafe = Failsafe.none(); + Call call = callFor("/test"); + + testFailure(failsafe, call, (f, e) -> { + assertEquals(e.getAttemptCount(), 1); + assertEquals(e.getExecutionCount(), 1); + }, java.net.ConnectException.class); + } + + public void testCancel() { + // Given + mockDelayedResponse(200, "foo", 1000); + FailsafeExecutor failsafe = Failsafe.none(); + Call call = callFor("/test"); + + // When / Then Sync + FailsafeCall failsafeCall = FailsafeCall.of(call, failsafe); + runInThread(() -> { + sleep(150); + failsafeCall.cancel(); + }); + assertThrows(failsafeCall::execute, IOException.class); + assertTrue(call.isCanceled()); + assertTrue(failsafeCall.isCanceled()); + + // When / Then Async + Call call2 = call.clone(); + FailsafeCall failsafeCall2 = FailsafeCall.of(call2, failsafe); + runInThread(() -> { + sleep(150); + failsafeCall2.cancel(); + }); + assertThrows(() -> failsafeCall2.executeAsync().get(), CancellationException.class); + assertTrue(call2.isCanceled()); + assertTrue(failsafeCall2.isCanceled()); + assertCalled("/test", 2); + } + + private Call callFor(String path) { + return client.newCall(new Request.Builder().url(URL + path).build()); + } + + private void mockResponse(int responseCode, String body) { + stubFor(get(urlPathEqualTo("/test")).willReturn( + aResponse().withStatus(responseCode).withHeader("Content-Type", "text/plain").withBody(body))); + } + + private void mockDelayedResponse(int responseCode, String body, int delayMillis) { + stubFor(get(urlEqualTo("/test")).willReturn( + aResponse().withStatus(responseCode).withFixedDelay(delayMillis).withBody(body))); + } + + private void assertCalled(String url, int times) { + verify(times, getRequestedFor(urlPathEqualTo(url))); + } +} diff --git a/modules/okhttp/src/test/java/dev/failsafe/okhttp/testing/OkHttpTesting.java b/modules/okhttp/src/test/java/dev/failsafe/okhttp/testing/OkHttpTesting.java new file mode 100644 index 00000000..c1975759 --- /dev/null +++ b/modules/okhttp/src/test/java/dev/failsafe/okhttp/testing/OkHttpTesting.java @@ -0,0 +1,98 @@ +package dev.failsafe.okhttp.testing; + +import dev.failsafe.FailsafeExecutor; +import dev.failsafe.event.EventListener; +import dev.failsafe.event.ExecutionCompletedEvent; + +import dev.failsafe.okhttp.FailsafeCall; +import dev.failsafe.testing.Testing; +import net.jodah.concurrentunit.Waiter; +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Function; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +public class OkHttpTesting extends Testing { + public void testRequest(FailsafeExecutor failsafe, Call when, Then then, int expectedStatus, + T expectedResult) { + test(failsafe, when, then, expectedStatus, expectedResult, null); + } + + @SafeVarargs + public final void testFailure(FailsafeExecutor failsafe, Call when, Then then, + Class... expectedExceptions) { + test(failsafe, when, then, 0, null, expectedExceptions); + } + + private void test(FailsafeExecutor failsafe, Call when, Then then, int expectedStatus, + T expectedResult, Class[] expectedExceptions) { + AtomicReference> futureRef = new AtomicReference<>(); + AtomicReference> completedEventRef = new AtomicReference<>(); + Waiter completionListenerWaiter = new Waiter(); + EventListener> setCompletedEventFn = e -> { + completedEventRef.set(e); + completionListenerWaiter.resume(); + }; + List> expected = new LinkedList<>(); + Class[] expectedExInner = expectedExceptions == null ? new Class[] {} : expectedExceptions; + Collections.addAll(expected, expectedExInner); + failsafe.onComplete(setCompletedEventFn); + + Runnable postTestFn = () -> { + ignoreExceptions(() -> completionListenerWaiter.await(5000)); + ExecutionCompletedEvent completedEvent = completedEventRef.get(); + if (expectedExceptions == null) { + assertEquals(completedEvent.getResult().code(), expectedStatus); + assertNull(completedEvent.getException()); + } else { + assertNull(completedEvent.getResult()); + assertMatches(completedEvent.getException(), expectedExceptions); + } + if (then != null) + then.accept(futureRef.get(), completedEvent); + }; + + Consumer assertResult = response -> { + String result = unwrapExceptions(() -> response.body().string()); + assertEquals(result, expectedResult); + assertEquals(response.code(), expectedStatus); + }; + + // Run sync test and assert result + System.out.println("\nRunning sync test"); + FailsafeCall failsafeCall = FailsafeCall.of(when, failsafe); + if (expectedExceptions == null) { + assertResult.accept(unwrapExceptions(failsafeCall::execute)); + } else { + assertThrows(failsafeCall::execute, expectedExceptions); + } + postTestFn.run(); + + if (expectedExInner.length > 0) + expected.add(0, ExecutionException.class); + + // Run async test and assert result + System.out.println("\nRunning async test"); + failsafeCall = failsafeCall.clone(); + CompletableFuture future = failsafeCall.executeAsync(); + futureRef.set(future); + if (expectedExInner.length == 0) { + assertResult.accept(unwrapExceptions(future::get)); + } else { + assertThrowsSup(future::get, expected); + } + postTestFn.run(); + } +} diff --git a/pom.xml b/pom.xml index 46d38a43..6e9c7bf7 100644 --- a/pom.xml +++ b/pom.xml @@ -2,16 +2,11 @@ 4.0.0 - - org.sonatype.oss - oss-parent - 7 - - + pom dev.failsafe - failsafe + failsafe-parent 3.2.2-SNAPSHOT - Failsafe + Failsafe Parent https://failsafe.dev @@ -35,6 +30,12 @@ https://github.com/failsafe-lib/failsafe + + core + examples + modules/okhttp + + @@ -55,26 +56,6 @@ 0.4.4 test - - - - io.reactivex - rxjava - 1.0.12 - test - - - io.netty - netty-all - 4.1.51.Final - test - - - io.vertx - vertx-core - 3.9.8 - test -