alibaba / alibaba/jetcache

多级缓存启用同步本地缓存后,关闭应用时视乎有问题

Open
#993 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
5.6k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

opendjk17,jetcache2.7.8,springboot3.5.7

手动创建了一个多级缓存:
```
@PostConstruct
public void init() {
QuickConfig qc = QuickConfig.newBuilder("userCache")
//.expire(Duration.ofSeconds(100))
.cacheType(CacheType.BOTH)
.syncLocal(true) // 开启本地同步后,关闭应用时报一个错
.localLimit(20)
.build();
userCache = cacheManager.getOrCreateCache(qc);
}
```

redis操作基于spring-data-redis,在应用关闭时,报了一个错:
```
2025-11-06T03:18:40.316+08:00 WARN 19044 --- [ionShutdownHook] d.r.c.l.LettucePoolingConnectionProvider : LettucePoolingConnectionProvider contains unreleased connections
2025-11-06T03:18:40.325+08:00 WARN 19044 --- [ionShutdownHook] o.s.d.r.l.RedisMessageListenerContainer : Unable to unsubscribe from subscriptions

org.springframework.data.redis.connection.PoolException: Returned connection io.lettuce.core.pubsub.StatefulRedisPubSubConnectionImpl@6e243864 was either previously returned or does not belong to this connection provider
at org.springframework.data.redis.connection.lettuce.LettucePoolingConnectionProvider.release(LettucePoolingConnectionProvider.java:166) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.release(LettuceConnectionFactory.java:1852) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.connection.lettuce.LettuceSubscription.doClose(LettuceSubscription.java:102) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.connection.util.AbstractSubscription.close(AbstractSubscription.java:105) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer$Subscriber.closeSubscription(RedisMessageListenerContainer.java:1361) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer$Subscriber.doUnsubscribe(RedisMessageListenerContainer.java:1324) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer$Subscriber.lambda$unsubscribeAll$2(RedisMessageListenerContainer.java:1317) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer$Subscriber.lambda$doInLock$9(RedisMessageListenerContainer.java:1445) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer$Subscriber.doInLock(RedisMessageListenerContainer.java:1455) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer$Subscriber.doInLock(RedisMessageListenerContainer.java:1444) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer$Subscriber.unsubscribeAll(RedisMessageListenerContainer.java:1312) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer.doUnsubscribe(RedisMessageListenerContainer.java:512) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer.stopListening(RedisMessageListenerContainer.java:494) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer.removeListener(RedisMessageListenerContainer.java:764) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer.removeMessageListener(RedisMessageListenerContainer.java:587) ~[spring-data-redis-3.5.5.jar:3.5.5]
at org.springframework.data.redis.listener.RedisMessageListenerContainer.removeMessageListener(RedisMessageListenerContainer.java:614) ~[spring-data-redis-3.5.5.jar:3.5.5]
at com.alicp.jetcache.redis.springdata.SpringDataBroadcastManager.close(SpringDataBroadcastManager.java:104) ~[jetcache-redis-springdata-2.7.8.jar:na]
at com.alicp.jetcache.SimpleCacheManager.lambda$close$0(SimpleCacheManager.java:44) ~[jetcache-core-2.7.8.jar:na]
at java.base/java.util.concurrent.ConcurrentHashMap.forEach(ConcurrentHashMap.java:1603) ~[na:na]
at com.alicp.jetcache.SimpleCacheManager.close(SimpleCacheManager.java:42) ~[jetcache-core-2.7.8.jar:na]
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:233) ~[spring-beans-6.2.12.jar:6.2.12]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:798) ~[spring-beans-6.2.12.jar:6.2.12]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:748) ~[spring-beans-6.2.12.jar:6.2.12]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1499) ~[spring-beans-6.2.12.jar:6.2.12]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:707) ~[spring-beans-6.2.12.jar:6.2.12]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1492) ~[spring-beans-6.2.12.jar:6.2.12]
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1222) ~[spring-context-6.2.12.jar:6.2.12]
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1183) ~[spring-context-6.2.12.jar:6.2.12]
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:1129) ~[spring-context-6.2.12.jar:6.2.12]
at org.springframework.boot.SpringApplicationShutdownHook.closeAndWait(SpringApplicationShutdownHook.java:147) ~[spring-boot-3.5.7.jar:3.5.7]
at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
at org.springframework.boot.SpringApplicationShutdownHook.run(SpringApplicationShutdownHook.java:116) ~[spring-boot-3.5.7.jar:3.5.7]
at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]
```

# AI解释:

根据错误信息,这是一个与 Redis 连接池相关的异常。错误发生在关闭 StatefulRedisPubSubConnection 连接时,提示该连接已经被归还或不属于当前连接提供者。
## 问题分析
这个错误通常出现在以下几种情况:
1. 重复释放连接:同一个连接被多次归还到连接池中
2. 连接管理不当:连接在使用完毕后没有正确关闭或被错误地重新使用
3. Spring Data Redis 与 JetCache 集成问题:特别是在应用关闭时,资源清理顺序不当

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with com.alicp.jetcache.redis.springdata.SpringDataBroadcastManager.close at line 104 and com.alicp.jetcache.SimpleCacheManager.close at line 42, then review the reported Spring Data Redis shutdown stack. Reproduce the provided Java 17, JetCache 2.7.8, and Spring Boot 3.5.7 configuration with syncLocal(true), and verify that application shutdown no longer reports unreleased or incorrectly returned Pub/Sub connections.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, redis, spring-boot
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.