clickhouse-java icon indicating copy to clipboard operation
clickhouse-java copied to clipboard

"R2dbcNonTransientResourceException: Connection validation failed" after connection is closed due to maxIdleTime

Open vkrot-innio opened this issue 2 years ago • 0 comments

Hi, I use clickhouse-r2dbc version 0.4.6 and connection pooling. After 30 minutes or inactivity (default value for maxIdleTime) connection is closed and no further queries run with existing connection factory. This is reproduction scenario:

import io.r2dbc.spi.Connection;
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryOptions;
import reactor.core.publisher.Flux;

public class ReproduceBug {
    public static void select1(ConnectionFactory connectionFactory) {
        Flux.usingWhen(connectionFactory.create(),
                connection -> {
                    var statement = connection.createStatement("select 1");
                    return statement.execute();
                }, Connection::close)
                .collectList()
                .block();
    }
    public static void main(String[] args) throws InterruptedException {
        var options = ConnectionFactoryOptions.parse(
                "r2dbc:pool:clickhouse:http://localhost:8123?maxIdleTime=PT1S"
        );
        ConnectionFactory connectionFactory = ConnectionFactories.get(options);

        select1(connectionFactory);
        Thread.sleep(2000L);
        select1(connectionFactory);
    }
}

Causes an error:

Exception in thread "main" io.r2dbc.spi.R2dbcNonTransientResourceException: Connection validation failed
	at io.r2dbc.pool.Validation.lambda$validate$2(Validation.java:45)
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:179)
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.request(FluxHandleFuseable.java:260)
	at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onSubscribe(MonoIgnoreElements.java:72)
	at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onSubscribe(FluxHandleFuseable.java:164)
	at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:68)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4495)
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263)
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at io.r2dbc.pool.MonoDiscardOnCancel.subscribe(MonoDiscardOnCancel.java:50)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165)
	at reactor.pool.AbstractPool$Borrower.deliver(AbstractPool.java:467)
	at reactor.pool.SimpleDequePool.lambda$drainLoop$8(SimpleDequePool.java:372)
	at reactor.core.scheduler.ImmediateScheduler.schedule(ImmediateScheduler.java:52)
	at reactor.pool.SimpleDequePool.drainLoop(SimpleDequePool.java:372)
	at reactor.pool.SimpleDequePool.pendingOffer(SimpleDequePool.java:604)
	at reactor.pool.SimpleDequePool.doAcquire(SimpleDequePool.java:298)
	at reactor.pool.AbstractPool$Borrower.request(AbstractPool.java:430)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2215)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
	at reactor.pool.SimpleDequePool$QueueBorrowerMono.subscribe(SimpleDequePool.java:722)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.FluxRetry$RetrySubscriber.resubscribe(FluxRetry.java:117)
	at reactor.core.publisher.MonoRetry.subscribeOrReturn(MonoRetry.java:50)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4480)
	at reactor.core.publisher.FluxUsingWhen.subscribe(FluxUsingWhen.java:104)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4495)
	at reactor.core.publisher.Mono.block(Mono.java:1711)
	at ReproduceBug.select1(ReproduceBug.java:16)
	at ReproduceBug.main(ReproduceBug.java:26)
	Suppressed: java.lang.Exception: #block terminated with an error
		at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:103)
		at reactor.core.publisher.Mono.block(Mono.java:1712)
		... 2 more

For sure works if I removed pool from connection string. Another workaround - set maxIdleTime to indefinite. Is that bug in clickhouse-java implementation or in r2dbc-pool?

vkrot-innio avatar Oct 25 '23 09:10 vkrot-innio