From d2fabf262013d5c7845c68fc485ab59429acc328 Mon Sep 17 00:00:00 2001 From: "A.Fink" Date: Mon, 20 Nov 2023 20:25:17 +0300 Subject: [PATCH] prevent arithmetic overflow and reduce allocations in time conversions --- .../core/apiimpl/FaultToleranceImpl.java | 24 +++--- .../faulttolerance/core/util/Durations.java | 60 ++++++++++++++ .../core/util/DurationsTest.java | 79 +++++++++++++++++++ .../FaultToleranceInterceptor.java | 45 +++++------ .../config/FaultToleranceOperation.java | 9 ++- .../faulttolerance/config/RetryConfig.java | 6 +- 6 files changed, 177 insertions(+), 46 deletions(-) create mode 100644 implementation/core/src/main/java/io/smallrye/faulttolerance/core/util/Durations.java create mode 100644 implementation/core/src/test/java/io/smallrye/faulttolerance/core/util/DurationsTest.java diff --git a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/FaultToleranceImpl.java b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/FaultToleranceImpl.java index 2fba2ee8..9347cebd 100644 --- a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/FaultToleranceImpl.java +++ b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/FaultToleranceImpl.java @@ -1,8 +1,8 @@ package io.smallrye.faulttolerance.core.apiimpl; import static io.smallrye.faulttolerance.core.Invocation.invocation; +import static io.smallrye.faulttolerance.core.util.Durations.timeInMillis; -import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.Collections; @@ -370,10 +370,6 @@ private FaultToleranceStrategy> buildAsyncStrategy(Builde return result; } - private static long getTimeInMs(long time, ChronoUnit unit) { - return Duration.of(time, unit).toMillis(); - } - private static ExceptionDecision createExceptionDecision(Collection> consideredExpected, Collection> consideredFailure, Predicate whenPredicate) { if (whenPredicate != null) { @@ -516,7 +512,7 @@ public CircuitBreakerBuilder delay(long value, ChronoUnit unit) { Preconditions.check(value, value >= 0, "Delay must be >= 0"); Preconditions.checkNotNull(unit, "Delay unit must be set"); - this.delayInMillis = getTimeInMs(value, unit); + this.delayInMillis = timeInMillis(value, unit); return this; } @@ -664,7 +660,7 @@ public RateLimitBuilder window(long value, ChronoUnit unit) { Preconditions.check(value, value >= 1, "Time window length must be >= 1"); Preconditions.checkNotNull(unit, "Time window length unit must be set"); - this.timeWindowInMillis = getTimeInMs(value, unit); + this.timeWindowInMillis = timeInMillis(value, unit); return this; } @@ -673,7 +669,7 @@ public RateLimitBuilder minSpacing(long value, ChronoUnit unit) { Preconditions.check(value, value >= 0, "Min spacing must be >= 0"); Preconditions.checkNotNull(unit, "Min spacing unit must be set"); - this.minSpacingInMillis = getTimeInMs(value, unit); + this.minSpacingInMillis = timeInMillis(value, unit); return this; } @@ -737,7 +733,7 @@ public RetryBuilder delay(long value, ChronoUnit unit) { Preconditions.check(value, value >= 0, "Delay must be >= 0"); Preconditions.checkNotNull(unit, "Delay unit must be set"); - this.delayInMillis = getTimeInMs(value, unit); + this.delayInMillis = timeInMillis(value, unit); return this; } @@ -746,7 +742,7 @@ public RetryBuilder maxDuration(long value, ChronoUnit unit) { Preconditions.check(value, value >= 0, "Max duration must be >= 0"); Preconditions.checkNotNull(unit, "Max duration unit must be set"); - this.maxDurationInMillis = getTimeInMs(value, unit); + this.maxDurationInMillis = timeInMillis(value, unit); return this; } @@ -755,7 +751,7 @@ public RetryBuilder jitter(long value, ChronoUnit unit) { Preconditions.check(value, value >= 0, "Jitter must be >= 0"); Preconditions.checkNotNull(unit, "Jitter unit must be set"); - this.jitterInMillis = getTimeInMs(value, unit); + this.jitterInMillis = timeInMillis(value, unit); return this; } @@ -857,7 +853,7 @@ public ExponentialBackoffBuilder maxDelay(long value, ChronoUnit unit) { Preconditions.check(value, value >= 0, "Max delay must be >= 0"); Preconditions.checkNotNull(unit, "Max delay unit must be set"); - this.maxDelayInMillis = getTimeInMs(value, unit); + this.maxDelayInMillis = timeInMillis(value, unit); return this; } @@ -882,7 +878,7 @@ public FibonacciBackoffBuilder maxDelay(long value, ChronoUnit unit) { Preconditions.check(value, value >= 0, "Max delay must be >= 0"); Preconditions.checkNotNull(unit, "Max delay unit must be set"); - this.maxDelayInMillis = getTimeInMs(value, unit); + this.maxDelayInMillis = timeInMillis(value, unit); return this; } @@ -935,7 +931,7 @@ public TimeoutBuilder duration(long value, ChronoUnit unit) { Preconditions.check(value, value >= 0, "Timeout duration must be >= 0"); Preconditions.checkNotNull(unit, "Timeout duration unit must be set"); - this.durationInMillis = getTimeInMs(value, unit); + this.durationInMillis = timeInMillis(value, unit); return this; } diff --git a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/util/Durations.java b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/util/Durations.java new file mode 100644 index 00000000..ba062c44 --- /dev/null +++ b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/util/Durations.java @@ -0,0 +1,60 @@ +package io.smallrye.faulttolerance.core.util; + +import java.time.temporal.ChronoUnit; +import java.util.concurrent.TimeUnit; + +public final class Durations { + private static final long SECONDS_IN_HALF_DAY = ChronoUnit.HALF_DAYS.getDuration().getSeconds(); + private static final long SECONDS_IN_WEEK = ChronoUnit.WEEKS.getDuration().getSeconds();; + private static final long SECONDS_IN_MONTH = ChronoUnit.MONTHS.getDuration().getSeconds();; + private static final long SECONDS_IN_YEAR = ChronoUnit.YEARS.getDuration().getSeconds();; + + private static final long MAX_HALF_DAYS = Long.MAX_VALUE / SECONDS_IN_HALF_DAY; + private static final long MAX_WEEKS = Long.MAX_VALUE / SECONDS_IN_WEEK; + private static final long MAX_MONTHS = Long.MAX_VALUE / SECONDS_IN_MONTH; + private static final long MAX_YEARS = Long.MAX_VALUE / SECONDS_IN_YEAR; + + public static long timeInMillis(long value, ChronoUnit unit) { + switch (unit) { + case NANOS: + return TimeUnit.NANOSECONDS.toMillis(value); + case MICROS: + return TimeUnit.MICROSECONDS.toMillis(value); + case MILLIS: + return value; + case SECONDS: + return TimeUnit.SECONDS.toMillis(value); + case MINUTES: + return TimeUnit.MINUTES.toMillis(value); + case HOURS: + return TimeUnit.HOURS.toMillis(value); + case HALF_DAYS: + return convert(value, MAX_HALF_DAYS, SECONDS_IN_HALF_DAY); + case DAYS: + return TimeUnit.DAYS.toMillis(value); + case WEEKS: + return convert(value, MAX_WEEKS, SECONDS_IN_WEEK); + case MONTHS: + return convert(value, MAX_MONTHS, SECONDS_IN_MONTH); + case YEARS: + return convert(value, MAX_YEARS, SECONDS_IN_YEAR); + default: + throw new IllegalArgumentException("Unsupported time unit: " + unit); + } + } + + private static long convert(long value, long maxInUnit, long secondsInUnit) { + if (value == Long.MIN_VALUE) { + return Long.MIN_VALUE; + } + + boolean negative = value < 0; + long abs = negative ? -value : value; + if (abs > maxInUnit) { + // `value * secondsInUnit` would overflow + return negative ? Long.MIN_VALUE : Long.MAX_VALUE; + } + + return TimeUnit.SECONDS.toMillis(value * secondsInUnit); + } +} diff --git a/implementation/core/src/test/java/io/smallrye/faulttolerance/core/util/DurationsTest.java b/implementation/core/src/test/java/io/smallrye/faulttolerance/core/util/DurationsTest.java new file mode 100644 index 00000000..f85e6da8 --- /dev/null +++ b/implementation/core/src/test/java/io/smallrye/faulttolerance/core/util/DurationsTest.java @@ -0,0 +1,79 @@ +package io.smallrye.faulttolerance.core.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; + +public class DurationsTest { + @Test + public void timeInMillis() { + assertThat(Durations.timeInMillis(5_000_000, ChronoUnit.NANOS)).isEqualTo(5); + assertThat(Durations.timeInMillis(5_000, ChronoUnit.MICROS)).isEqualTo(5); + assertThat(Durations.timeInMillis(5, ChronoUnit.MILLIS)).isEqualTo(5); + assertThat(Durations.timeInMillis(2, ChronoUnit.SECONDS)).isEqualTo(2000); + assertThat(Durations.timeInMillis(2, ChronoUnit.MINUTES)).isEqualTo(120_000); + assertThat(Durations.timeInMillis(3, ChronoUnit.HOURS)).isEqualTo(Duration.ofHours(3).toMillis()); + assertThat(Durations.timeInMillis(2, ChronoUnit.HALF_DAYS)).isEqualTo(Duration.ofDays(1).toMillis()); + assertThat(Durations.timeInMillis(8, ChronoUnit.HALF_DAYS)).isEqualTo(Duration.ofDays(4).toMillis()); + assertThat(Durations.timeInMillis(365, ChronoUnit.DAYS)).isEqualTo(Duration.ofDays(365).toMillis()); + assertThat(Durations.timeInMillis(7, ChronoUnit.WEEKS)).isEqualTo(Duration.ofDays(7 * 7).toMillis()); + assertThat(Durations.timeInMillis(17, ChronoUnit.WEEKS)).isEqualTo(Duration.ofDays(17 * 7).toMillis()); + assertThat(Durations.timeInMillis(12, ChronoUnit.MONTHS)).isEqualTo(ChronoUnit.YEARS.getDuration().toMillis()); + assertThat(Durations.timeInMillis(24, ChronoUnit.MONTHS)).isEqualTo(2 * ChronoUnit.YEARS.getDuration().toMillis()); + + assertThat(Durations.timeInMillis(0, ChronoUnit.HALF_DAYS)).isEqualTo(0); + assertThat(Durations.timeInMillis(4, ChronoUnit.HALF_DAYS)).isEqualTo(Duration.ofDays(2).toMillis()); + assertThat(Durations.timeInMillis(-4, ChronoUnit.HALF_DAYS)).isEqualTo(Duration.ofDays(-2).toMillis()); + assertThat(Durations.timeInMillis(0, ChronoUnit.DAYS)).isEqualTo(0); + assertThat(Durations.timeInMillis(4, ChronoUnit.DAYS)).isEqualTo(Duration.ofDays(4).toMillis()); + assertThat(Durations.timeInMillis(-4, ChronoUnit.DAYS)).isEqualTo(Duration.ofDays(-4).toMillis()); + assertThat(Durations.timeInMillis(0, ChronoUnit.WEEKS)).isEqualTo(0); + assertThat(Durations.timeInMillis(4, ChronoUnit.WEEKS)).isEqualTo(Duration.ofDays(4 * 7).toMillis()); + assertThat(Durations.timeInMillis(-4, ChronoUnit.WEEKS)).isEqualTo(Duration.ofDays(-4 * 7).toMillis()); + assertThat(Durations.timeInMillis(0, ChronoUnit.MONTHS)).isEqualTo(0); + assertThat(Durations.timeInMillis(7, ChronoUnit.MONTHS)).isEqualTo(7 * ChronoUnit.MONTHS.getDuration().toMillis()); + assertThat(Durations.timeInMillis(-7, ChronoUnit.MONTHS)).isEqualTo(-7 * ChronoUnit.MONTHS.getDuration().toMillis()); + + assertThat(Durations.timeInMillis(Long.MAX_VALUE, ChronoUnit.HOURS)).isEqualTo(Long.MAX_VALUE); + assertThat(Durations.timeInMillis(Long.MAX_VALUE, ChronoUnit.HALF_DAYS)).isEqualTo(Long.MAX_VALUE); + assertThat(Durations.timeInMillis(Long.MAX_VALUE, ChronoUnit.DAYS)).isEqualTo(Long.MAX_VALUE); + assertThat(Durations.timeInMillis(Long.MAX_VALUE, ChronoUnit.WEEKS)).isEqualTo(Long.MAX_VALUE); + assertThat(Durations.timeInMillis(Long.MAX_VALUE, ChronoUnit.MONTHS)).isEqualTo(Long.MAX_VALUE); + + assertThat(Durations.timeInMillis(Long.MAX_VALUE - 1, ChronoUnit.HOURS)).isEqualTo(Long.MAX_VALUE); + assertThat(Durations.timeInMillis(Long.MAX_VALUE - 1, ChronoUnit.HALF_DAYS)).isEqualTo(Long.MAX_VALUE); + assertThat(Durations.timeInMillis(Long.MAX_VALUE - 1, ChronoUnit.DAYS)).isEqualTo(Long.MAX_VALUE); + assertThat(Durations.timeInMillis(Long.MAX_VALUE - 1, ChronoUnit.WEEKS)).isEqualTo(Long.MAX_VALUE); + assertThat(Durations.timeInMillis(Long.MAX_VALUE - 1, ChronoUnit.MONTHS)).isEqualTo(Long.MAX_VALUE); + + assertThat(Durations.timeInMillis(Long.MIN_VALUE + 1, ChronoUnit.HOURS)).isEqualTo(Long.MIN_VALUE); + assertThat(Durations.timeInMillis(Long.MIN_VALUE + 1, ChronoUnit.HALF_DAYS)).isEqualTo(Long.MIN_VALUE); + assertThat(Durations.timeInMillis(Long.MIN_VALUE + 1, ChronoUnit.DAYS)).isEqualTo(Long.MIN_VALUE); + assertThat(Durations.timeInMillis(Long.MIN_VALUE + 1, ChronoUnit.WEEKS)).isEqualTo(Long.MIN_VALUE); + assertThat(Durations.timeInMillis(Long.MIN_VALUE + 1, ChronoUnit.MONTHS)).isEqualTo(Long.MIN_VALUE); + + assertThat(Durations.timeInMillis(Long.MIN_VALUE, ChronoUnit.HOURS)).isEqualTo(Long.MIN_VALUE); + assertThat(Durations.timeInMillis(Long.MIN_VALUE, ChronoUnit.HALF_DAYS)).isEqualTo(Long.MIN_VALUE); + assertThat(Durations.timeInMillis(Long.MIN_VALUE, ChronoUnit.DAYS)).isEqualTo(Long.MIN_VALUE); + assertThat(Durations.timeInMillis(Long.MIN_VALUE, ChronoUnit.WEEKS)).isEqualTo(Long.MIN_VALUE); + assertThat(Durations.timeInMillis(Long.MIN_VALUE, ChronoUnit.MONTHS)).isEqualTo(Long.MIN_VALUE); + } + + @Test + public void timeInMillis_random() { + for (ChronoUnit unit : List.of(ChronoUnit.NANOS, ChronoUnit.MICROS, ChronoUnit.MILLIS, ChronoUnit.SECONDS, + ChronoUnit.MINUTES, ChronoUnit.HOURS, ChronoUnit.HALF_DAYS, ChronoUnit.DAYS)) { + for (int i = 0; i < 1_000_000; i++) { + long value = ThreadLocalRandom.current().nextLong(Integer.MIN_VALUE * 1000L, Integer.MAX_VALUE * 1000L); + assertThat(Durations.timeInMillis(value, unit)) + .isEqualTo(TimeUnit.MILLISECONDS.convert(Duration.of(value, unit))); + } + } + } +} diff --git a/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/FaultToleranceInterceptor.java b/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/FaultToleranceInterceptor.java index 332408f9..96fdd134 100644 --- a/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/FaultToleranceInterceptor.java +++ b/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/FaultToleranceInterceptor.java @@ -17,12 +17,11 @@ package io.smallrye.faulttolerance; import static io.smallrye.faulttolerance.core.Invocation.invocation; +import static io.smallrye.faulttolerance.core.util.Durations.timeInMillis; import static io.smallrye.faulttolerance.core.util.SneakyThrow.sneakyThrow; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.time.Duration; -import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.UUID; import java.util.concurrent.Callable; @@ -296,21 +295,21 @@ private FaultToleranceStrategy> prepareAsyncStrategy(Faul } if (operation.hasTimeout()) { - long timeoutMs = getTimeInMs(operation.getTimeout().value(), operation.getTimeout().unit()); + long timeoutMs = timeInMillis(operation.getTimeout().value(), operation.getTimeout().unit()); result = new CompletionStageTimeout<>(result, point.toString(), timeoutMs, timer); } if (operation.hasRateLimit()) { result = new CompletionStageRateLimit<>(result, point.toString(), operation.getRateLimit().value(), - getTimeInMs(operation.getRateLimit().window(), operation.getRateLimit().windowUnit()), - getTimeInMs(operation.getRateLimit().minSpacing(), operation.getRateLimit().minSpacingUnit()), + timeInMillis(operation.getRateLimit().window(), operation.getRateLimit().windowUnit()), + timeInMillis(operation.getRateLimit().minSpacing(), operation.getRateLimit().minSpacingUnit()), operation.getRateLimit().type(), SystemStopwatch.INSTANCE); } if (operation.hasCircuitBreaker()) { - long delayInMillis = getTimeInMs(operation.getCircuitBreaker().delay(), operation.getCircuitBreaker().delayUnit()); + long delayInMillis = timeInMillis(operation.getCircuitBreaker().delay(), operation.getCircuitBreaker().delayUnit()); result = new CompletionStageCircuitBreaker<>(result, point.toString(), createExceptionDecision(operation.getCircuitBreaker().skipOn(), operation.getCircuitBreaker().failOn()), delayInMillis, @@ -327,7 +326,7 @@ private FaultToleranceStrategy> prepareAsyncStrategy(Faul } if (operation.hasRetry()) { - long maxDurationMs = getTimeInMs(operation.getRetry().maxDuration(), operation.getRetry().durationUnit()); + long maxDurationMs = timeInMillis(operation.getRetry().maxDuration(), operation.getRetry().durationUnit()); Supplier backoff = prepareRetryBackoff(operation); @@ -366,21 +365,21 @@ private FaultToleranceStrategy prepareSyncStrategy(FaultToleranceOperatio } if (operation.hasTimeout()) { - long timeoutMs = getTimeInMs(operation.getTimeout().value(), operation.getTimeout().unit()); + long timeoutMs = timeInMillis(operation.getTimeout().value(), operation.getTimeout().unit()); result = new Timeout<>(result, point.toString(), timeoutMs, timer); } if (operation.hasRateLimit()) { result = new RateLimit<>(result, point.toString(), operation.getRateLimit().value(), - getTimeInMs(operation.getRateLimit().window(), operation.getRateLimit().windowUnit()), - getTimeInMs(operation.getRateLimit().minSpacing(), operation.getRateLimit().minSpacingUnit()), + timeInMillis(operation.getRateLimit().window(), operation.getRateLimit().windowUnit()), + timeInMillis(operation.getRateLimit().minSpacing(), operation.getRateLimit().minSpacingUnit()), operation.getRateLimit().type(), SystemStopwatch.INSTANCE); } if (operation.hasCircuitBreaker()) { - long delayInMillis = getTimeInMs(operation.getCircuitBreaker().delay(), operation.getCircuitBreaker().delayUnit()); + long delayInMillis = timeInMillis(operation.getCircuitBreaker().delay(), operation.getCircuitBreaker().delayUnit()); result = new CircuitBreaker<>(result, point.toString(), createExceptionDecision(operation.getCircuitBreaker().skipOn(), operation.getCircuitBreaker().failOn()), delayInMillis, @@ -397,7 +396,7 @@ private FaultToleranceStrategy prepareSyncStrategy(FaultToleranceOperatio } if (operation.hasRetry()) { - long maxDurationMs = getTimeInMs(operation.getRetry().maxDuration(), operation.getRetry().durationUnit()); + long maxDurationMs = timeInMillis(operation.getRetry().maxDuration(), operation.getRetry().durationUnit()); Supplier backoff = prepareRetryBackoff(operation); @@ -437,7 +436,7 @@ private FaultToleranceStrategy> prepareFutureStrategy(FaultToleran } if (operation.hasTimeout()) { - long timeoutMs = getTimeInMs(operation.getTimeout().value(), operation.getTimeout().unit()); + long timeoutMs = timeInMillis(operation.getTimeout().value(), operation.getTimeout().unit()); Timeout> timeout = new Timeout<>(result, point.toString(), timeoutMs, timer); result = new AsyncTimeout<>(timeout, asyncExecutor); } @@ -445,14 +444,14 @@ private FaultToleranceStrategy> prepareFutureStrategy(FaultToleran if (operation.hasRateLimit()) { result = new RateLimit<>(result, point.toString(), operation.getRateLimit().value(), - getTimeInMs(operation.getRateLimit().window(), operation.getRateLimit().windowUnit()), - getTimeInMs(operation.getRateLimit().minSpacing(), operation.getRateLimit().minSpacingUnit()), + timeInMillis(operation.getRateLimit().window(), operation.getRateLimit().windowUnit()), + timeInMillis(operation.getRateLimit().minSpacing(), operation.getRateLimit().minSpacingUnit()), operation.getRateLimit().type(), SystemStopwatch.INSTANCE); } if (operation.hasCircuitBreaker()) { - long delayInMillis = getTimeInMs(operation.getCircuitBreaker().delay(), operation.getCircuitBreaker().delayUnit()); + long delayInMillis = timeInMillis(operation.getCircuitBreaker().delay(), operation.getCircuitBreaker().delayUnit()); result = new CircuitBreaker<>(result, point.toString(), createExceptionDecision(operation.getCircuitBreaker().skipOn(), operation.getCircuitBreaker().failOn()), delayInMillis, @@ -469,7 +468,7 @@ private FaultToleranceStrategy> prepareFutureStrategy(FaultToleran } if (operation.hasRetry()) { - long maxDurationMs = getTimeInMs(operation.getRetry().maxDuration(), operation.getRetry().durationUnit()); + long maxDurationMs = timeInMillis(operation.getRetry().maxDuration(), operation.getRetry().durationUnit()); Supplier backoff = prepareRetryBackoff(operation); @@ -499,18 +498,18 @@ private FaultToleranceStrategy> prepareFutureStrategy(FaultToleran } private Supplier prepareRetryBackoff(FaultToleranceOperation operation) { - long delayMs = getTimeInMs(operation.getRetry().delay(), operation.getRetry().delayUnit()); + long delayMs = timeInMillis(operation.getRetry().delay(), operation.getRetry().delayUnit()); - long jitterMs = getTimeInMs(operation.getRetry().jitter(), operation.getRetry().jitterDelayUnit()); + long jitterMs = timeInMillis(operation.getRetry().jitter(), operation.getRetry().jitterDelayUnit()); Jitter jitter = jitterMs == 0 ? Jitter.ZERO : new RandomJitter(jitterMs); if (operation.hasExponentialBackoff()) { int factor = operation.getExponentialBackoff().factor(); - long maxDelay = getTimeInMs(operation.getExponentialBackoff().maxDelay(), + long maxDelay = timeInMillis(operation.getExponentialBackoff().maxDelay(), operation.getExponentialBackoff().maxDelayUnit()); return () -> new ExponentialBackOff(delayMs, factor, jitter, maxDelay); } else if (operation.hasFibonacciBackoff()) { - long maxDelay = getTimeInMs(operation.getFibonacciBackoff().maxDelay(), + long maxDelay = timeInMillis(operation.getFibonacciBackoff().maxDelay(), operation.getFibonacciBackoff().maxDelayUnit()); return () -> new FibonacciBackOff(delayMs, jitter, maxDelay); } else if (operation.hasCustomBackoff()) { @@ -580,10 +579,6 @@ private FallbackFunction prepareFallbackFunction(InterceptionPoint point, return fallbackFunction; } - private long getTimeInMs(long time, ChronoUnit unit) { - return Duration.of(time, unit).toMillis(); - } - private ExceptionDecision createExceptionDecision(Class[] consideredExpected, Class[] consideredFailure) { return new SetBasedExceptionDecision(createSetOfThrowables(consideredFailure), diff --git a/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/FaultToleranceOperation.java b/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/FaultToleranceOperation.java index ea11a4fe..706f773a 100644 --- a/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/FaultToleranceOperation.java +++ b/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/FaultToleranceOperation.java @@ -15,8 +15,9 @@ */ package io.smallrye.faulttolerance.config; +import static io.smallrye.faulttolerance.core.util.Durations.timeInMillis; + import java.lang.annotation.Annotation; -import java.time.Duration; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -397,10 +398,10 @@ private void validateRetryBackoff() { } if (retry != null) { - long retryMaxDuration = Duration.of(retry.maxDuration(), retry.durationUnit()).toMillis(); + long retryMaxDuration = timeInMillis(retry.maxDuration(), retry.durationUnit()); if (retryMaxDuration > 0) { if (exponentialBackoff != null) { - long maxDelay = Duration.of(exponentialBackoff.maxDelay(), exponentialBackoff.maxDelayUnit()).toMillis(); + long maxDelay = timeInMillis(exponentialBackoff.maxDelay(), exponentialBackoff.maxDelayUnit()); if (retryMaxDuration <= maxDelay) { throw new FaultToleranceDefinitionException("Invalid @ExponentialBackoff on " + methodDescriptor + ": @Retry.maxDuration should be greater than maxDelay"); @@ -408,7 +409,7 @@ private void validateRetryBackoff() { } if (fibonacciBackoff != null) { - long maxDelay = Duration.of(fibonacciBackoff.maxDelay(), fibonacciBackoff.maxDelayUnit()).toMillis(); + long maxDelay = timeInMillis(fibonacciBackoff.maxDelay(), fibonacciBackoff.maxDelayUnit()); if (retryMaxDuration <= maxDelay) { throw new FaultToleranceDefinitionException("Invalid @FibonacciBackoff on " + methodDescriptor + ": @Retry.maxDuration should be greater than maxDelay"); diff --git a/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/RetryConfig.java b/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/RetryConfig.java index 9e792b19..6dedf88a 100644 --- a/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/RetryConfig.java +++ b/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/RetryConfig.java @@ -1,6 +1,6 @@ package io.smallrye.faulttolerance.config; -import java.time.Duration; +import static io.smallrye.faulttolerance.core.util.Durations.timeInMillis; import org.eclipse.microprofile.faulttolerance.Retry; import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException; @@ -26,9 +26,9 @@ default void validate() { throw new FaultToleranceDefinitionException(INVALID_RETRY_ON + method() + ": maxDuration shouldn't be lower than 0"); } - long maxDuration = Duration.of(maxDuration(), durationUnit()).toMillis(); + long maxDuration = timeInMillis(maxDuration(), durationUnit()); if (maxDuration > 0) { - long delay = Duration.of(delay(), delayUnit()).toMillis(); + long delay = timeInMillis(delay(), delayUnit()); if (maxDuration <= delay) { throw new FaultToleranceDefinitionException(INVALID_RETRY_ON + method() + ": maxDuration should be greater than delay");