Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

`JedisConnectionFactory.start()` leaks the pool when `preparePool()` fails

Aperta
#3,482 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 5 giorni

Nessuno ha ancora preso questa issue.

  • #3484 di @night-crawlr — chiusa senza merge

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
35/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Ferma
Stack tecnologico
java, redis
Ambito
backend, databases

Direzione di ricerca

Start in JedisConnectionFactory.start() and compare its failure path with the resource cleanup in stop(). The issue provides a reproducer using minIdle(1) and an unreachable Redis server; use it to check that a failed start releases the pool and leaves the factory retryable. An open linked pull request (#3484) already addresses this work.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

status: waiting-for-triage

Affected: 3.4.2 onwards (since #3072), including 4.0.x, 4.1.x and main. On 4.1+ the pool leak needs the legacy client path (setUseUnifiedJedis(false), the deprecated JedisPoolConfig constructors, or a Jedis version without RedisClient).

start() sets the state to STARTING, creates the pool, then calls pool.preparePool(). With minIdle > 0 and a Redis that is down or stalling, preparePool() throws and start() rethrows it as PoolException. After that:

  • the state stays STARTING. stop() only acts on STARTED, so neither stop() nor destroy() closes the pool (destroy() only sets DESTROYED);
  • a second start() silently does nothing and getConnection() fails, so the factory can never be used or retried;
  • the pool field is private, so the caller cannot close it either;
  • in a Spring container, a bean whose afterPropertiesSet() threw is never destroyed, so the only place the pool can be released is inside start() itself.

The abandoned GenericObjectPool stays registered in JMX (enabled by default), which keeps it reachable, and its evictor keeps running (JedisPoolConfig sets a 30 s interval). While Redis is down, every eviction run tries to create the missing idle connections and fails; once Redis is reachable again, every orphaned pool keeps reopening about minIdle connections (idle ones are evicted after 60 s and recreated) for the life of the JVM. With sentinels configured and the master unreachable, the same happens to the JedisSentinelPool, whose MasterListener threads also keep running.

An application that builds a new factory after a failure (for example one factory per Redis server, created on demand) leaks one pool per failed attempt, so an outage of a few minutes can leave enough orphaned pools behind to keep the server at maxclients after it has recovered.

The "cannot be retried" part is not limited to the legacy path: if creating the unified client throws (for example a cluster that is unreachable at startup), the factory also stays in STARTING.

Reproducer:

JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMinIdle(1);

JedisConnectionFactory factory = new JedisConnectionFactory(
        new RedisStandaloneConfiguration("127.0.0.1", 6390),          // nothing listening
        JedisClientConfiguration.builder().usePooling().poolConfig(poolConfig).build());
factory.setUseUnifiedJedis(false);                                   // 4.1+ only

factory.afterPropertiesSet();   // PoolException: Could not prepare the pool
factory.destroy();              // sets DESTROYED, releases nothing

// org.apache.commons.pool2:type=GenericObjectPool,* is still registered, and the
// commons-pool-evictor thread keeps trying to create minIdle connections every 30 s.

Expected: a start() that fails releases what it created and returns the factory to a state from which start() can be retried.

(Not covered here: if no sentinel answers, the JedisSentinelPool constructor itself throws after its pool was registered, so that pool never reaches Spring Data.)

I'm happy to send a PR: run the body of start() in a try/catch, dispose the created resources the same way stop() does, restore the previous state and rethrow.

Lingua principale
Java
Stelle
1.9k
Fork
1.3k
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di spring-projects/spring-data-redis

Tutte le issue di spring-projects/spring-data-redis

Issue simili

Altre issue su Java

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.