Search code examples
spring-bootspring-data-r2dbcr2dbcr2dbc-postgresql

Spring Boot and R2DBC: io.r2dbc.spi.R2dbcNonTransientResourceException: Connection validation failed


I'm using Spring Boot 2.4.9 with WebFlux and R2DBC, deployed using the standard Netty server. The database is PostgreSQL. There is only one R2DBC repository class in the app.

R2DBC is configured in application.properties with these properties:

spring.r2dbc.username=xxx
spring.r2dbc.password=yyy
spring.r2dbc.url=r2dbc:postgresql://$host:port/database

According to the documentation, a connection pool is automatically configured because r2dbc:pool is on the classpath.

We occasionally incur this exception when the repository class is used:

org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection; nested exception is io.r2dbc.spi.R2dbcNonTransientResourceException: Connection validation failed
    at org.springframework.r2dbc.connection.ConnectionFactoryUtils.lambda$getConnection$0(ConnectionFactoryUtils.java:88)
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ Handler com.myco.ManagementController#viewMessages() [DispatcherHandler]
    |_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ HTTP GET "/management/management-messages" [ExceptionHandlingWebHandler]
Stack trace:
        at org.springframework.r2dbc.connection.ConnectionFactoryUtils.lambda$getConnection$0(ConnectionFactoryUtils.java:88)
        at reactor.core.publisher.Mono.lambda$onErrorMap$31(Mono.java:3676)
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94)
        at 

(There's more in the stack, but this is all that seems relevant)

The nested io.r2dbc.spi.R2dbcNonTransientResourceException: Connection validation failed appears to be the culprit, but I've searched and searched and cannot figure out what I might be doing wrong.

If it helps at all, the application does use these properties, which point to the same database, and are only used to give a regular JDBC connection to a Flyway bean:

spring.datasource.username=xxx
spring.datasource.password=yyy
spring.datasource.url=jdbc:postgresql://host:port/database

Just in case that might interfere with R2DBC, but I can't imagine that I would.

In addition, it seems like after the application server first starts up, we don't see the error for something like the first 10 or so minutes, but the error will start appearing after that. The error only occurs occasionally too; it doesn't happen all the time.

The only way that I can reproduce the error on my workstation is when I stop and restart the Docker container in which PostgreSQL is running, while leaving the application server running the whole time. I then get the same error, but then the error is persistent and happens every time, where in our production environment, the error is intermittent.

I've used Spring Boot + R2DBC on other production applications (but those used MySQL) and have never seen this problem before.

What is causing that connection validation error and how can I fix it?

Thank you!


Solution

  • As it turns out, updating Postgres and R2DBC dependencies fixed the problem. I replaced this dependency:

    implementation 'io.r2dbc:r2dbc-postgresql'
    

    with these dependencies:

    implementation 'org.postgresql:r2dbc-postgresql:0.9.0.RELEASE'
    implementation 'io.r2dbc:r2dbc-pool:0.9.0.RELEASE'
    implementation 'io.r2dbc:r2dbc-spi:0.9.1.RELEASE'
    

    Note that for the r2dbc-postgresql dependency, the group changed from io.r2dbc to org.postgres.

    This comment in the R2DBC pool issues was especially helpful.