From 354e7b147eb00efeb24119225039e577627cab39 Mon Sep 17 00:00:00 2001 From: dajiaohuang Date: Sun, 25 Oct 2026 12:40:34 +0800 Subject: [PATCH] [POOL-432] Guard monitor recovery when no adder exists Generated-by: OpenAI Codex gpt-6-luna --- .../impl/ResilientPooledObjectFactory.java | 6 +++-- .../TestResilientPooledObjectFactory.java | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/pool3/impl/ResilientPooledObjectFactory.java b/src/main/java/org/apache/commons/pool3/impl/ResilientPooledObjectFactory.java index 53f5ea0bf..c1ca2d39c 100644 --- a/src/main/java/org/apache/commons/pool3/impl/ResilientPooledObjectFactory.java +++ b/src/main/java/org/apache/commons/pool3/impl/ResilientPooledObjectFactory.java @@ -479,8 +479,10 @@ protected void runChecks() { // Kill adder thread and set up to true upStart = Instant.now(); up = true; - adder.kill(); - adder = null; + if (adder != null) { + adder.kill(); + adder = null; + } } } diff --git a/src/test/java/org/apache/commons/pool3/impl/TestResilientPooledObjectFactory.java b/src/test/java/org/apache/commons/pool3/impl/TestResilientPooledObjectFactory.java index 242106c0f..35ee5058d 100644 --- a/src/test/java/org/apache/commons/pool3/impl/TestResilientPooledObjectFactory.java +++ b/src/test/java/org/apache/commons/pool3/impl/TestResilientPooledObjectFactory.java @@ -16,8 +16,10 @@ */ package org.apache.commons.pool3.impl; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.Duration; @@ -257,6 +259,30 @@ public void run() { assertFalse(rf.isMonitorRunning()); } + @Test + void testRecoveryWithoutAdderDoesNotThrowWhenFactoryComesBackUp() throws Exception { + final FailingFactory ff = new FailingFactory(); + ff.setSilentFail(false); + final ResilientPooledObjectFactory rf = new ResilientPooledObjectFactory<>(ff, + 2, Duration.ofMillis(10), Duration.ofMinutes(10), Duration.ofMillis(10)); + final GenericObjectPool pool = new GenericObjectPool<>(rf); + rf.setPool(pool); + + ff.crash(); + assertThrows(Exception.class, rf::makeObject); + rf.runChecks(); + assertFalse(rf.isUp()); + assertFalse(rf.isAdderRunning()); + + ff.recover(); + rf.makeObject(); + rf.makeObject(); + assertDoesNotThrow(rf::runChecks); + assertTrue(rf.isUp()); + assertFalse(rf.isAdderRunning()); + pool.close(); + } + @Test void testTransientFailure() throws Exception { final FailingFactory ff = new FailingFactory();