quarkus: [jdbc-mysql extension] MySQL high availability datasource health check not supported in native Quarkus

I am using the jdbc-mysql Quarkus extension for connecting my Quarkus application to a MySQL cluster. My datatsource URL is like:

jdbc:mysql:replication://host/db

As you can see, I am using the Connector/J feature replication as described on https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-master-slave-replication-connection.html

While this works fine running Quarkus running in JVM, a Quarkus native fails to do the datasource health check.

When running my Quarkus application as a native, the health endpoint returns:

$ curl localhost:8080/health
{   
    "status": "DOWN",
    "checks": [
        {   
            "name": "Database connections health check",
            "status": "DOWN",
            "data": {
                "default": "Unable to execute the validation check for the default DataSource: !InvalidLoadBalanceExceptionChecker!"
            }
        }
    ]
}

The corresponding exception is

2020-03-18 13:31:17,255 WARN  [io.agr.pool] {} Datasource '<default>': !InvalidLoadBalanceExceptionChecker!
2020-03-18 13:31:17,255 DEBUG [io.agr.pool] {} Cause: : java.sql.SQLException: !InvalidLoadBalanceExceptionChecker!
        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129)
        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
        at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:73)
        at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:85)
        at com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy.<init>(LoadBalancedConnectionProxy.java:244)
        at com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy.createProxyInstance(LoadBalancedConnectionProxy.java:120)
        at com.mysql.cj.jdbc.ha.ReplicationConnectionProxy.initializeSlavesConnection(ReplicationConnectionProxy.java:448)
        at com.mysql.cj.jdbc.ha.ReplicationConnectionProxy.<init>(ReplicationConnectionProxy.java:168)
        at com.mysql.cj.jdbc.ha.ReplicationConnectionProxy.createProxyInstance(ReplicationConnectionProxy.java:88)
        at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:209)
        at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:200)
        at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:390)
        at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:372)
        at java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:65)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.lang.Thread.run(Thread.java:834)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:527)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
Caused by: com.mysql.cj.exceptions.WrongArgumentException: !InvalidLoadBalanceExceptionChecker!
        at java.lang.reflect.Constructor.newInstance(Constructor.java:490)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
        at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:151)
        at com.mysql.cj.util.Util.getInstance(Util.java:169)
        at com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy.<init>(LoadBalancedConnectionProxy.java:239)
        ... 15 more
Caused by: java.lang.ClassNotFoundException: com.mysql.cj.jdbc.ha.StandardLoadBalanceExceptionChecker
        at com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:60)
        at java.lang.Class.forName(DynamicHub.java:1211)
        at com.mysql.cj.util.Util.getInstance(Util.java:167)
        ... 16 more

Adding com.mysql.cj.jdbc.ha.StandardLoadBalanceExceptionChecker to the reflection-config.json seems to be only the tip of the iceberg, doing so results in exceptions of kind

2020-03-18 13:18:02,839 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] {} HTTP Request to /health failed, error id: 8865e180-03db-4b52-b335-efa4e0f8223b-1: com.oracle.svm.core.jdk.UnsupportedFeatureError: Proxy class defined by interfaces [interface com.mysql.cj.jdbc.ha.LoadBalancedConnection, interface com.mysql.cj.jdbc.JdbcConnection] not found. Generating proxy classes at runtime is not supported. Proxy classes need to be defined at image build time by specifying the list of interfaces that they implement. To define proxy classes use -H:DynamicProxyConfigurationFiles=<comma-separated-config-files> and -H:DynamicProxyConfigurationResources=<comma-separated-config-resources> options.
        at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:101)
        at com.oracle.svm.reflect.proxy.DynamicProxySupport.getProxyClass(DynamicProxySupport.java:113)
        at java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:66)
        at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1006)
        at com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy.createProxyInstance(LoadBalancedConnectionProxy.java:121)
        at com.mysql.cj.jdbc.ha.ReplicationConnectionProxy.initializeSlavesConnection(ReplicationConnectionProxy.java:448)
        at com.mysql.cj.jdbc.ha.ReplicationConnectionProxy.<init>(ReplicationConnectionProxy.java:168)
        at com.mysql.cj.jdbc.ha.ReplicationConnectionProxy.createProxyInstance(ReplicationConnectionProxy.java:88)
        at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:209)
        at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:200)
        at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:390)
        at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:372)
        at java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:65)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1126)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.lang.Thread.run(Thread.java:834)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:527)

Workaround Removing replication from the datasource URL “solves” the issue.

Environment

  • Java: v11
  • Quarkus: 1.3.0.Final
  • Build tool: Gradle

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 18 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Yesterday I presented Quarkus including native image to my company. Would not have worked out without your fix. What a timing guys!

Hi guys,

I have given building Quarkus another chance. -DskipDocs does not help (-Dmaven.javadoc.skip=true neither), so I excluded Maven module extensions -> “hibernate-search-elasticsearch” (and integration-tests -> “hibernate-search-elasticsearch”) from build.

Putting it all together: The latest version of Quarkus (commit https://github.com/quarkusio/quarkus/commit/9db47139f07e451bc60110fcf333b577fe056556) works fine related to this issue 😃

Thanks a lot guys for feedback, and even backporting!