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 6f208fd56..324d5b489 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 @@ -585,6 +585,13 @@ public BulkheadBuilder onFinished(Runnable callback) { @Override public Builder done() { + try { + Math.addExact(limit, queueSize); + } catch (ArithmeticException e) { + throw new IllegalStateException("Bulkhead capacity overflow, " + limit + " + " + queueSize + + " = " + (limit + queueSize)); + } + parent.bulkheadBuilder = this; return parent; } diff --git a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/GuardImpl.java b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/GuardImpl.java index 9aabd931f..58817c3eb 100644 --- a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/GuardImpl.java +++ b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/GuardImpl.java @@ -411,6 +411,13 @@ public BulkheadBuilder onFinished(Runnable callback) { @Override public Builder done() { + try { + Math.addExact(limit, queueSize); + } catch (ArithmeticException e) { + throw new IllegalStateException("Bulkhead capacity overflow, " + limit + " + " + queueSize + + " = " + (limit + queueSize)); + } + parent.bulkheadBuilder = this; return parent; } diff --git a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/TypedGuardImpl.java b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/TypedGuardImpl.java index c53ccaa27..3a600a57d 100644 --- a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/TypedGuardImpl.java +++ b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/apiimpl/TypedGuardImpl.java @@ -432,6 +432,13 @@ public BulkheadBuilder onFinished(Runnable callback) { @Override public Builder done() { + try { + Math.addExact(limit, queueSize); + } catch (ArithmeticException e) { + throw new IllegalStateException("Bulkhead capacity overflow, " + limit + " + " + queueSize + + " = " + (limit + queueSize)); + } + parent.bulkheadBuilder = this; return parent; } diff --git a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/bulkhead/Bulkhead.java b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/bulkhead/Bulkhead.java index dc6d7d263..16ae38422 100644 --- a/implementation/core/src/main/java/io/smallrye/faulttolerance/core/bulkhead/Bulkhead.java +++ b/implementation/core/src/main/java/io/smallrye/faulttolerance/core/bulkhead/Bulkhead.java @@ -43,7 +43,7 @@ public Bulkhead(FaultToleranceStrategy delegate, String description, int size this.delegate = delegate; this.description = description; this.queue = new ConcurrentLinkedDeque<>(); - this.capacitySemaphore = new Semaphore(size + queueSize, true); + this.capacitySemaphore = new Semaphore(Math.addExact(size, queueSize), true); this.workSemaphore = new Semaphore(size, true); this.syncQueueing = syncQueueing; } diff --git a/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/BulkheadConfig.java b/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/BulkheadConfig.java index a4247d3da..1744676cf 100644 --- a/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/BulkheadConfig.java +++ b/implementation/fault-tolerance/src/main/java/io/smallrye/faulttolerance/config/BulkheadConfig.java @@ -20,5 +20,13 @@ default void validate() { throw new FaultToleranceDefinitionException(INVALID_BULKHEAD_ON + method() + ": waitingTaskQueue shouldn't be lower than 1"); } + + try { + Math.addExact(value(), waitingTaskQueue()); + } catch (ArithmeticException e) { + throw new FaultToleranceDefinitionException(INVALID_BULKHEAD_ON + method() + + ": bulkhead capacity overflow, " + value() + " + " + waitingTaskQueue() + + " = " + (value() + waitingTaskQueue())); + } } } diff --git a/testsuite/basic/src/test/java/io/smallrye/faulttolerance/bulkhead/capacity/overflow/BulkheadCapacityOverflowTest.java b/testsuite/basic/src/test/java/io/smallrye/faulttolerance/bulkhead/capacity/overflow/BulkheadCapacityOverflowTest.java new file mode 100644 index 000000000..a73983682 --- /dev/null +++ b/testsuite/basic/src/test/java/io/smallrye/faulttolerance/bulkhead/capacity/overflow/BulkheadCapacityOverflowTest.java @@ -0,0 +1,14 @@ +package io.smallrye.faulttolerance.bulkhead.capacity.overflow; + +import io.smallrye.faulttolerance.util.ExpectedDeploymentException; +import io.smallrye.faulttolerance.util.FaultToleranceBasicTest; +import jakarta.enterprise.inject.spi.DefinitionException; +import org.junit.jupiter.api.Test; + +@FaultToleranceBasicTest +@ExpectedDeploymentException(DefinitionException.class) +public class BulkheadCapacityOverflowTest { + @Test + public void test(MyService ignored) { + } +} diff --git a/testsuite/basic/src/test/java/io/smallrye/faulttolerance/bulkhead/capacity/overflow/MyService.java b/testsuite/basic/src/test/java/io/smallrye/faulttolerance/bulkhead/capacity/overflow/MyService.java new file mode 100644 index 000000000..81f038955 --- /dev/null +++ b/testsuite/basic/src/test/java/io/smallrye/faulttolerance/bulkhead/capacity/overflow/MyService.java @@ -0,0 +1,19 @@ +package io.smallrye.faulttolerance.bulkhead.capacity.overflow; + +import jakarta.enterprise.context.ApplicationScoped; +import org.eclipse.microprofile.faulttolerance.Asynchronous; +import org.eclipse.microprofile.faulttolerance.Bulkhead; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import static java.util.concurrent.CompletableFuture.completedFuture; + +@ApplicationScoped +public class MyService { + @Asynchronous + @Bulkhead(value = 1, waitingTaskQueue = Integer.MAX_VALUE) + public CompletionStage hello() { + return completedFuture("hello"); + } +}