Skip to content

Commit

Permalink
Change Timeout to TimeLimiter.
Browse files Browse the repository at this point in the history
Decorate Future<T> and Future<T> Supplier to return Callable<T>.
  • Loading branch information
maarek committed May 29, 2017
1 parent a84955b commit a245f39
Show file tree
Hide file tree
Showing 16 changed files with 416 additions and 495 deletions.
2 changes: 1 addition & 1 deletion resilience4j-all/build.gradle
Expand Up @@ -10,6 +10,6 @@ dependencies {
compile project(':resilience4j-retry')
compile project(':resilience4j-consumer')
compile project(':resilience4j-cache')
compile project(':resilience4j-timeout')
compile project(':resilience4j-timelimiter')
testCompile project(':resilience4j-test')
}
Expand Up @@ -12,7 +12,6 @@
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.retry.AsyncRetry;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.timeout.Timeout;
import io.vavr.CheckedFunction0;
import io.vavr.CheckedFunction1;
import io.vavr.CheckedRunnable;
Expand Down Expand Up @@ -87,11 +86,6 @@ public DecorateSupplier<T> withBulkhead(Bulkhead bulkhead) {
return this;
}

public DecorateSupplier<T> withTimeout(Timeout timeout) {
supplier = Timeout.decorateSupplier(timeout, supplier);
return this;
}

public Supplier<T> decorate() {
return supplier;
}
Expand Down Expand Up @@ -128,11 +122,6 @@ public DecorateFunction<T, R> withBulkhead(Bulkhead bulkhead) {
return this;
}

public DecorateFunction<T, R> withTimeout(Timeout timeout) {
function = Timeout.decorateFunction(timeout, function);
return this;
}

public Function<T, R> decorate() {
return function;
}
Expand Down Expand Up @@ -169,11 +158,6 @@ public DecorateRunnable withBulkhead(Bulkhead bulkhead) {
return this;
}

public DecorateRunnable withTimeout(Timeout timeout) {
runnable = Timeout.decorateRunnable(timeout, runnable);
return this;
}

public Runnable decorate() {
return runnable;
}
Expand Down Expand Up @@ -215,11 +199,6 @@ public DecorateCheckedSupplier<T> withBulkhead(Bulkhead bulkhead) {
return this;
}

public DecorateCheckedSupplier<T> withTimeout(Timeout timeout) {
supplier = Timeout.decorateCheckedSupplier(timeout, supplier);
return this;
}

public CheckedFunction0<T> decorate() {
return supplier;
}
Expand Down Expand Up @@ -256,11 +235,6 @@ public DecorateCheckedFunction<T, R> withBulkhead(Bulkhead bulkhead) {
return this;
}

public DecorateCheckedFunction<T, R> withTimeout(Timeout timeout) {
function = Timeout.decorateCheckedFunction(timeout, function);
return this;
}

public CheckedFunction1<T, R> decorate() {
return function;
}
Expand Down Expand Up @@ -297,11 +271,6 @@ public DecorateCheckedRunnable withBulkhead(Bulkhead bulkhead) {
return this;
}

public DecorateCheckedRunnable withTimeout(Timeout timeout) {
runnable = Timeout.decorateCheckedRunnable(timeout, runnable);
return this;
}

public CheckedRunnable decorate() {
return runnable;
}
Expand Down Expand Up @@ -371,11 +340,6 @@ public DecorateConsumer<T> withBulkhead(Bulkhead bulkhead) {
return this;
}

public DecorateConsumer<T> withTimeout(Timeout timeout) {
consumer = Timeout.decorateConsumer(timeout, consumer);
return this;
}

public Consumer<T> decorate() {
return consumer;
}
Expand Down
File renamed without changes.
@@ -0,0 +1,129 @@
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 at a configurable rate.
*/
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 which is restricted by a TimeLimiter.
*
* @param timeLimiter the {@link TimeLimiter}
* @param future the original future
* @param <T> the type of results supplied supplier
* @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 which is restricted by a TimeLimiter.
*
* @param timeLimiter the {@link TimeLimiter}
* @param futureSupplier the original future supplier
* @param <T> the type of results supplied 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 decorated Future.
*
* @param future the original Future
*
* @return the result of the decorated Future.
* @param <T> the result type of the future
* @param <F> the type of 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 decorated Future Supplier.
*
* @param futureSupplier the original future supplier
*
* @return the result of the Future.
* @param <T> the result type of the future
* @param <F> the type of 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();
}
}
@@ -1,55 +1,61 @@
package io.github.resilience4j.timeout;
package io.github.resilience4j.timelimiter;

import java.time.Duration;

import static java.util.Objects.requireNonNull;

public class TimeoutConfig {
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 TimeoutConfig() {
private TimeLimiterConfig() {
}

/**
* Returns a builder to create a custom TimeoutConfig.
* Returns a builder to create a custom TimeLimiterConfig.
*
* @return a {@link TimeoutConfig.Builder}
* @return a {@link TimeLimiterConfig.Builder}
*/
public static Builder custom() {
return new Builder();
}

/**
* Creates a default Timeout configuration.
* Creates a default TimeLimiter configuration.
*
* @return a default Timeout configuration.
* @return a default TimeLimiter configuration.
*/
public static TimeoutConfig ofDefaults(){
public static TimeLimiterConfig ofDefaults(){
return new Builder().build();
}

public Duration getTimeoutDuration() {
return timeoutDuration;
}

public boolean shouldCancelRunningFuture() {
return cancelRunningFuture;
}

@Override public String toString() {
return "TimeoutConfig{" +
return "TimeLimiterConfig{" +
"timeoutDuration=" + timeoutDuration +
"cancelRunningFuture=" + cancelRunningFuture +
'}';
}

public static class Builder {

private TimeoutConfig config = new TimeoutConfig();
private TimeLimiterConfig config = new TimeLimiterConfig();

/**
* Builds a TimeoutConfig
* Builds a TimeLimiterConfig
*
* @return the TimeoutConfig
* @return the TimeLimiterConfig
*/
public TimeoutConfig build() {
public TimeLimiterConfig build() {
return config;
}

Expand All @@ -58,17 +64,28 @@ public TimeoutConfig build() {
* Default value is 5 seconds.
*
* @param timeoutDuration the timeout Duration
* @return the TimeoutConfig.Builder
* @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);
}

}
@@ -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;
}
}

0 comments on commit a245f39

Please sign in to comment.