Micronaut Data PostgresSql R2DBC GraalVM native image can't connect to a database
Expected Behavior
Expected everything to work same as the JVM version
Actual Behaviour
The application doesn't connect to PostgresSql when packaged natively into a container(dockerBuildNative).
[reactor-tcp-nio-1] ERROR i.m.http.server.RouteExecutor - Unexpected error occurred: Cannot connect to xxx.xx.xx.xxx/:5432
io.r2dbc.postgresql.PostgresqlConnectionFactory$PostgresConnectionException: Cannot connect to xxx.xx.xx.xxx/:5432
at io.r2dbc.postgresql.PostgresqlConnectionFactory.cannotConnect(PostgresqlConnectionFactory.java:216)
at reactor.core.publisher.Mono.lambda$onErrorMap$31(Mono.java:3733)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onError(ReactorSubscriber.java:64)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:129)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57)
at reactor.core.publisher.MonoDelayUntil$DelayUntilCoordinator.complete(MonoDelayUntil.java:418)
at reactor.core.publisher.MonoDelayUntil$DelayUntilTrigger.onComplete(MonoDelayUntil.java:531)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onComplete(ReactorSubscriber.java:71)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onComplete(FluxHandle.java:220)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onComplete(ReactorSubscriber.java:71)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onComplete(FluxHandle.java:220)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onComplete(ReactorSubscriber.java:71)
at reactor.core.publisher.FluxCreate$BaseSink.complete(FluxCreate.java:460)
at reactor.core.publisher.FluxCreate$BufferAsyncSink.drain(FluxCreate.java:805)
at reactor.core.publisher.FluxCreate$BufferAsyncSink.complete(FluxCreate.java:753)
at reactor.core.publisher.FluxCreate$SerializedFluxSink.drainLoop(FluxCreate.java:247)
at reactor.core.publisher.FluxCreate$SerializedFluxSink.drain(FluxCreate.java:213)
at reactor.core.publisher.FluxCreate$SerializedFluxSink.complete(FluxCreate.java:204)
at io.r2dbc.postgresql.client.ReactorNettyClient$Conversation.complete(ReactorNettyClient.java:619)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.emit(ReactorNettyClient.java:885)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.onNext(ReactorNettyClient.java:761)
at io.r2dbc.postgresql.client.ReactorNettyClient$BackendMessageSubscriber.onNext(ReactorNettyClient.java:667)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57)
at reactor.core.publisher.FluxHandle$HandleSubscriber.onNext(FluxHandle.java:126)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:200)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
at io.micronaut.reactive.reactor.instrument.ReactorSubscriber.onNext(ReactorSubscriber.java:57)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:279)
at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:388)
at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:404)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:93)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:299)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:995)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:833)
at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704)
at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202)
Caused by: java.lang.IllegalArgumentException: Class java.time.Instant[] is instantiated reflectively but was never registered.Register the class by adding "unsafeAllocated" for the class in reflect-config.json.
at com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets.arrayHubErrorStub(SubstrateAllocationSnippets.java:252)
at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1054)
at io.r2dbc.postgresql.codec.CachedCodecLookup.afterCodecAdded(CachedCodecLookup.java:70)
at io.r2dbc.postgresql.codec.DefaultCodecs.(DefaultCodecs.java:82)
at io.r2dbc.postgresql.codec.DefaultCodecs.(DefaultCodecs.java:66)
at io.r2dbc.postgresql.PostgresqlConnectionFactory.lambda$doCreateConnection$13(PostgresqlConnectionFactory.java:157)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125)
################
The exact same application connects to a database when packaged into a jar and ran inside a container(dockerBuild).
Steps To Reproduce
Micronaut Data R2DBC PostgresSql
and use dockerBuildNative to package the application. Fails on the first request to the application
Environment Information
OS: MacOS Monterey.
JDK: 17.0.4
Docker: 4.10.1
Example Application
No response
Version
3.5.3
I'm able to reproduce the same issue with R2DBC driver, the JDBC works fine with a native image.
Do we have any update on this issue?
R2DBC makes use of reflection to instantiate some classes. A workaround to be able to use the native image would be adding a reflect-config.json file in the path src/main/resources/META-INF/native-image/your.group/your.artifact/reflect-config.json
with the following content:
[
{
"name": "java.time.Instant[]",
"allPublicMethods": true,
"allDeclaredConstructors": true
},
{
"name": "java.time.ZonedDateTime[]",
"allPublicMethods": true,
"allDeclaredConstructors": true
},
{
"name": "java.net.URL[]",
"allPublicMethods": true,
"allDeclaredConstructors": true
},
{
"name": "java.util.Date[]",
"allPublicMethods": true,
"allDeclaredConstructors": true
}
]
Not sure if those are all the reflection instantiation usages by R2DBC, but, with this, you should be able to connect to the DB using R2DBC and native image.
Yes its working if you also add
{ "name": "java.net.URI[]", "allPublicMethods": true, "allDeclaredConstructors": true }
I'm observing similar symptoms with Micronaut 3.7.3, Gradle plugin 3.6.4. Application fails readiness probe when deployed on K8s cluster using assembled native image. From the logs I see that request to database hangs and never returns. If I use non-native image with the same components the issue is gone. If I disable K8s health checks for R2DBC issue is gone. Mentioned workaround doesn't help.
I'm observing similar symptoms with Micronaut 3.7.3, Gradle plugin 3.6.4. Application fails readiness probe when deployed on K8s cluster using assembled native image. From the logs I see that request to database hangs and never returns. If I use non-native image with the same components the issue is gone. If I disable K8s health checks for R2DBC issue is gone. Mentioned workaround doesn't help.
@seprokof I had the same issue with the mysql connections. I upgraded to the latest micronaut 3.8.3, gradle plugin: 3.7.0 and I used GraalVM 22.3 (sdkman java identifier: 22.3.r17-grl). And the issue disappeared. May be it will solve your problem too.
isn't this related to (and also fixed by) this issue? https://github.com/pgjdbc/r2dbc-postgresql/issues/549
I'm also getting same error. But I'm not using graalvm. I'm using docker build to create image and when run this image, I get below error
{"@timestamp":"2023-08-01T04:47:04.731Z","@version":"1","message":"Health indicator [r2dbc-connection-factory] reported exception: io.r2dbc.postgresql.PostgresqlConnectionFactory$PostgresConnectionException: Cannot connect to localhost/<unresolved>:2709","logger_name":"io.micronaut.management.health.indicator.HealthResult","thread_name":"reactor-tcp-epoll-5","level":"ERROR","level_value":40000,"stack_trace":"io.r2dbc.postgresql.PostgresqlConnectionFactory$PostgresConnectionException: Cannot connect to localhost/<unresolved>:2709\n\tat io.r2dbc.postgresql.PostgresqlConnectionFactory.cannotConnect(PostgresqlConnectionFactory.java:188)
@msupic please take a look
I succeeded to reproduce the original issue (submitted by @javaCoincidence) when creating a service using Micronaut CLI 3.5.3
. The Micronaut CLI 3.5.3
creates a service with org.postgresql:r2dbc-postgresql:0.9.1.RELEASE
which doesn't contain any native image metadata. After I replaced 0.9.1.RELEASE
with 1.0.2.RELEASE
, the issue has been fixed since 1.0.2.RELEASE
contains all necessary metadata.