diff --git a/reactor-pool/src/main/java/reactor/pool/SimpleDequePool.java b/reactor-pool/src/main/java/reactor/pool/SimpleDequePool.java index 4b937bf8..135622d6 100644 --- a/reactor-pool/src/main/java/reactor/pool/SimpleDequePool.java +++ b/reactor-pool/src/main/java/reactor/pool/SimpleDequePool.java @@ -230,6 +230,9 @@ public Mono warmup() { recordInteractionTimestamp(); int initSize = poolConfig.allocationStrategy() .getPermits(0); + if (initSize <= 0) { + return Mono.just(0); + } @SuppressWarnings({ "unchecked", "rawtypes" }) //rawtypes added since javac actually complains Mono[] allWarmups = new Mono[initSize]; for (int i = 0; i < initSize; i++) { diff --git a/reactor-pool/src/test/java/reactor/pool/CommonPoolTest.java b/reactor-pool/src/test/java/reactor/pool/CommonPoolTest.java index d00e2967..e93e59f2 100644 --- a/reactor-pool/src/test/java/reactor/pool/CommonPoolTest.java +++ b/reactor-pool/src/test/java/reactor/pool/CommonPoolTest.java @@ -2730,4 +2730,43 @@ void recordsPendingCountAndLatencies(PoolStyle configAdjuster) { .as("pending error latency") .isGreaterThanOrEqualTo(1L); } + + + @ParameterizedTestWithName + @MethodSource("allPools") + void gh180_warmupIdempotent(PoolStyle configAdjuster) { + VirtualTimeScheduler vts = VirtualTimeScheduler.create(); + + AtomicInteger allocCounter = new AtomicInteger(); + Mono allocator = Mono.fromCallable(allocCounter::incrementAndGet); + + PoolBuilder builder = + PoolBuilder.from(allocator) + .sizeBetween(10, 10) + .evictionPredicate((poolable, metadata) -> metadata.idleTime() >= 4000) + .evictInBackground(Duration.ofSeconds(5), vts) + .clock(SchedulerClock.of(vts)); + + InstrumentedPool pool = configAdjuster.apply(builder); + pool.warmup().block(); + assertThat(allocCounter).as("allocations").hasValue(10); + assertThat(pool.metrics().allocatedSize()).as("allocatedSize").isEqualTo(10); + + assertThatCode(() -> vts.advanceTimeBy(Duration.ofSeconds(10))).doesNotThrowAnyException(); + + assertThat(pool.metrics().allocatedSize()).as("allocatedSize").isEqualTo(0); + assertThat(allocCounter).as("allocations").hasValue(10); + + pool.warmup().block(); + assertThat(allocCounter).as("allocations").hasValue(20); + assertThat(pool.metrics().allocatedSize()).as("allocatedSize").isEqualTo(10); + + // Since warmup can be called at anytime, calling warmup again should not cause any troubles and should keep the + // pool unchanged. + pool.warmup().block(); + assertThat(allocCounter).as("allocations").hasValue(20); + assertThat(pool.metrics().allocatedSize()).as("allocatedSize").isEqualTo(10); + + pool.disposeLater().block(Duration.ofSeconds(3)); + } }