redis / lettuce

Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.
https://lettuce.io
MIT License
5.37k stars 960 forks source link

Pool exhausted, Java 21 and Virtual Threads #2867

Open jkvargas opened 4 months ago

jkvargas commented 4 months ago

Hi, I am getting Pool exhausted when I pass a ClientResources which does use an executor with virtual threads.

java.util.concurrent.CompletionException: java.util.NoSuchElementException: Pool exhausted
    at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(Unknown Source) ~[?:?]
    at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(Unknown Source) ~[?:?]
    at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(Unknown Source) ~[?:?]
    at java.base/java.util.concurrent.CompletableFuture.thenApply(Unknown Source) ~[?:?]
    at io.lettuce.core.support.AsyncConnectionPoolSupport$1.acquire(AsyncConnectionPoolSupport.java:189) ~[lettuce-core-6.3.2.RELEASE.jar:6.3.2.RELEASE/8941aea]

This is my java code,

var executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory());
EventLoopGroup customEventLoopGroup = new NioEventLoopGroup(0, executor);
var clientResources =
        ClientResources.builder().eventExecutorGroup(customEventLoopGroup).build();
RedisClient.create(clientResources, ...);

how can I fix this? I am using lettuce-core-6.3.2.RELEASE.jar running on a linux container. Thanks!

arulned commented 4 months ago

I am also interested in this. I could not find a clear documentation on how to use virtual threads in lettuce. Appreciate a good reference.

prathyand commented 3 months ago

Hi, I am getting Pool exhausted when I pass a ClientResources which does use an executor with virtual threads.

java.util.concurrent.CompletionException: java.util.NoSuchElementException: Pool exhausted
  at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(Unknown Source) ~[?:?]
  at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(Unknown Source) ~[?:?]
  at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(Unknown Source) ~[?:?]
  at java.base/java.util.concurrent.CompletableFuture.thenApply(Unknown Source) ~[?:?]
  at io.lettuce.core.support.AsyncConnectionPoolSupport$1.acquire(AsyncConnectionPoolSupport.java:189) ~[lettuce-core-6.3.2.RELEASE.jar:6.3.2.RELEASE/8941aea]

This is my java code,

var executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory());
EventLoopGroup customEventLoopGroup = new NioEventLoopGroup(0, executor);
var clientResources =
        ClientResources.builder().eventExecutorGroup(customEventLoopGroup).build();
RedisClient.create(clientResources, ...);

how can I fix this? I am using lettuce-core-6.3.2.RELEASE.jar running on a linux container. Thanks!

Hey I'm not quite sure if I know the solution, but you might want to look into newVirtualThreadPerTaskExecutor()

tishun commented 3 months ago

Hey @jkvargas ,

        Executor executor = Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory());
        EventLoopGroup customEventLoopGroup = new NioEventLoopGroup(0, executor);
        var clientResources =
                ClientResources.builder().eventExecutorGroup(customEventLoopGroup).build();

        try (RedisClient clusterClient = RedisClient.create(clientResources, redisURI)) {
            StatefulRedisConnection<String, String> connection = clusterClient.connect();
            connection.sync().set("key", "value");
        }

I tried your code and it worked for me, could this be some environment issue with your JVM / JDK?

Hey I'm not quite sure if I know the solution, but you might want to look into newVirtualThreadPerTaskExecutor()

Both newVirtualThreadPerTaskExecutor() and newThreadPerTaskExecutor() should do the job, see this blog post.

yszzu1 commented 1 month ago

redisTemplate.getRequiredConnectionFactory().getConnection();

org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.SharedConnection#getConnection, getNativeConnection() is stucked, there is synchronized , after upgrade to springboot 3.3.2 which is using lock, it's still stucked.

ref: https://github.com/spring-projects/spring-data-redis/issues/2690