-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
508 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
dependencies { | ||
compile ( libraries.rxjava2) | ||
} |
127 changes: 127 additions & 0 deletions
127
resilience4j-timelimiter/src/main/java/io/github/resilience4j/timelimiter/TimeLimiter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package io.github.resilience4j.timelimiter; | ||
|
||
import io.github.resilience4j.timelimiter.internal.TimeLimiterContext; | ||
|
||
import java.time.Duration; | ||
import java.util.concurrent.Callable; | ||
import java.util.concurrent.Future; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.TimeoutException; | ||
import java.util.function.Supplier; | ||
|
||
/** | ||
* A TimeLimiter decorator stops execution after a configurable duration. | ||
*/ | ||
public interface TimeLimiter { | ||
|
||
/** | ||
* Creates a TimeLimiter decorator with a default TimeLimiterConfig configuration. | ||
* | ||
* @return The {@link TimeLimiter} | ||
*/ | ||
static TimeLimiter ofDefaults() { | ||
return new TimeLimiterContext(TimeLimiterConfig.ofDefaults()); | ||
} | ||
|
||
/** | ||
* Creates a TimeLimiter decorator with a TimeLimiterConfig configuration. | ||
* | ||
* @param timeLimiterConfig the TimeLimiterConfig | ||
* @return The {@link TimeLimiter} | ||
*/ | ||
static TimeLimiter of(TimeLimiterConfig timeLimiterConfig) { | ||
return new TimeLimiterContext(timeLimiterConfig); | ||
} | ||
|
||
/** | ||
* Creates a TimeLimiter decorator with a timeout Duration. | ||
* | ||
* @param timeoutDuration the timeout Duration | ||
* @return The {@link TimeLimiter} | ||
*/ | ||
static TimeLimiter of(Duration timeoutDuration) { | ||
TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom() | ||
.timeoutDuration(timeoutDuration) | ||
.build(); | ||
|
||
return new TimeLimiterContext(timeLimiterConfig); | ||
} | ||
|
||
/** | ||
* Creates a Callable that is restricted by a TimeLimiter. | ||
* | ||
* @param timeLimiter the TimeLimiter | ||
* @param future the original future | ||
* @param <T> the type of results supplied by the future | ||
* @param <F> the future type supplied | ||
* @return a future which is restricted by a {@link TimeLimiter}. | ||
*/ | ||
static <T, F extends Future<T>> Callable<T> decorateFuture(final TimeLimiter timeLimiter, final F future) { | ||
return () -> { | ||
try { | ||
return future.get(timeLimiter.getTimeLimiterConfig().getTimeoutDuration().toMillis(), TimeUnit.MILLISECONDS); | ||
} catch (TimeoutException e) { | ||
if (timeLimiter.getTimeLimiterConfig().shouldCancelRunningFuture()) { | ||
future.cancel(true); | ||
} | ||
throw e; | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Creates a Callback that is restricted by a TimeLimiter. | ||
* | ||
* @param timeLimiter the TimeLimiter | ||
* @param futureSupplier the original future supplier | ||
* @param <T> the type of results supplied by the supplier | ||
* @param <F> the future type supplied | ||
* @return a future supplier which is restricted by a {@link TimeLimiter}. | ||
*/ | ||
static <T, F extends Future<T>> Callable<T> decorateFutureSupplier(TimeLimiter timeLimiter, Supplier<F> futureSupplier) { | ||
return () -> { | ||
Future<T> future = futureSupplier.get(); | ||
try { | ||
return future.get(timeLimiter.getTimeLimiterConfig().getTimeoutDuration().toMillis(), TimeUnit.MILLISECONDS); | ||
} catch (TimeoutException e) { | ||
if(timeLimiter.getTimeLimiterConfig().shouldCancelRunningFuture()){ | ||
future.cancel(true); | ||
} | ||
throw e; | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Get the TimeLimiterConfig of this TimeLimiter decorator. | ||
* | ||
* @return the TimeLimiterConfig of this TimeLimiter decorator | ||
*/ | ||
TimeLimiterConfig getTimeLimiterConfig(); | ||
|
||
/** | ||
* Decorates and executes the Future. | ||
* | ||
* @param future the original Future | ||
* @param <T> the result type of the future | ||
* @param <F> the type of Future | ||
* @return the result of the decorated Future. | ||
* @throws Exception if unable to compute a result | ||
*/ | ||
default <T, F extends Future<T>> T executeFuture(F future) throws Exception { | ||
return decorateFuture(this, future).call(); | ||
} | ||
|
||
/** | ||
* Decorates and executes the Future Supplier. | ||
* | ||
* @param futureSupplier the original future supplier | ||
* @param <T> the result type of the future | ||
* @param <F> the type of Future | ||
* @return the result of the Future. | ||
* @throws Exception if unable to compute a result | ||
*/ | ||
default <T, F extends Future<T>> T executeFutureSupplier(Supplier<F> futureSupplier) throws Exception { | ||
return decorateFutureSupplier(this, futureSupplier).call(); | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
...nce4j-timelimiter/src/main/java/io/github/resilience4j/timelimiter/TimeLimiterConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package io.github.resilience4j.timelimiter; | ||
|
||
import java.time.Duration; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
public class TimeLimiterConfig { | ||
private static final String TIMEOUT_DURATION_MUST_NOT_BE_NULL = "TimeoutDuration must not be null"; | ||
|
||
private Duration timeoutDuration = Duration.ofSeconds(1); | ||
private boolean cancelRunningFuture = true; | ||
|
||
private TimeLimiterConfig() { | ||
} | ||
|
||
/** | ||
* Returns a builder to create a custom TimeLimiterConfig. | ||
* | ||
* @return a {@link TimeLimiterConfig.Builder} | ||
*/ | ||
public static Builder custom() { | ||
return new Builder(); | ||
} | ||
|
||
/** | ||
* Creates a default TimeLimiter configuration. | ||
* | ||
* @return a default TimeLimiter configuration. | ||
*/ | ||
public static TimeLimiterConfig ofDefaults(){ | ||
return new Builder().build(); | ||
} | ||
|
||
public Duration getTimeoutDuration() { | ||
return timeoutDuration; | ||
} | ||
|
||
public boolean shouldCancelRunningFuture() { | ||
return cancelRunningFuture; | ||
} | ||
|
||
@Override public String toString() { | ||
return "TimeLimiterConfig{" + | ||
"timeoutDuration=" + timeoutDuration + | ||
"cancelRunningFuture=" + cancelRunningFuture + | ||
'}'; | ||
} | ||
|
||
public static class Builder { | ||
|
||
private TimeLimiterConfig config = new TimeLimiterConfig(); | ||
|
||
/** | ||
* Builds a TimeLimiterConfig | ||
* | ||
* @return the TimeLimiterConfig | ||
*/ | ||
public TimeLimiterConfig build() { | ||
return config; | ||
} | ||
|
||
/** | ||
* Configures the thread execution timeout | ||
* Default value is 1 second. | ||
* | ||
* @param timeoutDuration the timeout Duration | ||
* @return the TimeLimiterConfig.Builder | ||
*/ | ||
public Builder timeoutDuration(final Duration timeoutDuration) { | ||
config.timeoutDuration = checkTimeoutDuration(timeoutDuration); | ||
return this; | ||
} | ||
|
||
/** | ||
* Configures whether cancel is called on the running future | ||
* Defaults to TRUE | ||
* | ||
* @param cancelRunningFuture to cancel or not | ||
* @return the TimeLimiterConfig.Builder | ||
*/ | ||
public Builder cancelRunningFuture(final boolean cancelRunningFuture) { | ||
config.cancelRunningFuture = cancelRunningFuture; | ||
return this; | ||
} | ||
|
||
} | ||
|
||
private static Duration checkTimeoutDuration(final Duration timeoutDuration) { | ||
return requireNonNull(timeoutDuration, TIMEOUT_DURATION_MUST_NOT_BE_NULL); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
...limiter/src/main/java/io/github/resilience4j/timelimiter/internal/TimeLimiterContext.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package io.github.resilience4j.timelimiter.internal; | ||
|
||
import io.github.resilience4j.timelimiter.TimeLimiter; | ||
import io.github.resilience4j.timelimiter.TimeLimiterConfig; | ||
|
||
public class TimeLimiterContext implements TimeLimiter { | ||
private final TimeLimiterConfig timeLimiterConfig; | ||
|
||
public TimeLimiterContext(TimeLimiterConfig timeLimiterConfig) { | ||
this.timeLimiterConfig = timeLimiterConfig; | ||
} | ||
|
||
@Override | ||
public TimeLimiterConfig getTimeLimiterConfig() { | ||
return timeLimiterConfig; | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
...j-timelimiter/src/test/java/io/github/resilience4j/timelimiter/TimeLimiterConfigTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package io.github.resilience4j.timelimiter; | ||
|
||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.rules.ExpectedException; | ||
|
||
import java.time.Duration; | ||
|
||
import static org.assertj.core.api.BDDAssertions.then; | ||
|
||
public class TimeLimiterConfigTest { | ||
|
||
private static final Duration TIMEOUT = Duration.ofSeconds(5); | ||
private static final boolean SHOULD_CANCEL = false; | ||
private static final String TIMEOUT_DURATION_MUST_NOT_BE_NULL = "TimeoutDuration must not be null"; | ||
private static final String TIMEOUT_TO_STRING = "TimeLimiterConfig{timeoutDuration=PT1ScancelRunningFuture=true}"; | ||
|
||
@Rule | ||
public ExpectedException exception = ExpectedException.none(); | ||
|
||
|
||
@Test | ||
public void builderPositive() { | ||
TimeLimiterConfig config = TimeLimiterConfig.custom() | ||
.timeoutDuration(TIMEOUT) | ||
.cancelRunningFuture(SHOULD_CANCEL) | ||
.build(); | ||
|
||
then(config.getTimeoutDuration()).isEqualTo(TIMEOUT); | ||
then(config.shouldCancelRunningFuture()).isEqualTo(SHOULD_CANCEL); | ||
} | ||
|
||
@Test | ||
public void defaultConstruction() { | ||
TimeLimiterConfig config = TimeLimiterConfig.ofDefaults(); | ||
then(config.getTimeoutDuration()).isEqualTo(Duration.ofSeconds(1)); | ||
then(config.shouldCancelRunningFuture()).isTrue(); | ||
} | ||
|
||
@Test | ||
public void builderTimeoutIsNull() { | ||
exception.expect(NullPointerException.class); | ||
exception.expectMessage(TIMEOUT_DURATION_MUST_NOT_BE_NULL); | ||
|
||
TimeLimiterConfig.custom() | ||
.timeoutDuration(null); | ||
} | ||
|
||
@Test | ||
public void configToString() { | ||
then(TimeLimiterConfig.ofDefaults().toString()).isEqualTo(TIMEOUT_TO_STRING); | ||
} | ||
} |
Oops, something went wrong.