Failed to obtain R2DBC Connection Java Spring - java

I am getting following exeption connecting to Mssql Server.
> org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection; nested exception is java.net.UnknownHostException: failed to resolve '' after 10 queries
at org.springframework.r2dbc.connection.ConnectionFactoryUtils.lambda$getConnection$0(ConnectionFactoryUtils.java:88) ~[spring-r2dbc-5.3.2.jar:5.3.2]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
|_ checkpoint ⇢ Handler com.reactive.testreactive.controller.TestStreamController#findAll() [DispatcherHandler]
|_ checkpoint ⇢ HTTP GET "/test" [ExceptionHandlingWebHandler]
I connected to JDBC with the same configuration in properties but having an issue while trying to connect to R2DBC. Happens on rest and not on starting an app.
#Bean
public MssqlConnectionFactory connectionFactory() {
return new MssqlConnectionFactory(MssqlConnectionConfiguration.builder()
.host("host")
.port(1433)
.database("DataBase")
.username("username")
.password("password")
.build());
}

Do you use absolutely the same configuration?
Because if you are starting using R2DBC you should replace database URL: jdbc:postgresql://... -> r2dbc:postgresql://

If anyone still looking for solution, I'm adding solution below.
First, make sure your database host is visible. By looking at your error statement which says -- failed to resolve '' after 10 queries, means it is empty ''. The way that you have defined the host name is not correct. If you are injecting the host value from properties, you might want to cross check that and then follow the steps below.
If you are configuring through YMLs, you can use below configurations:
spring:
data:
r2dbc:
repositories:
enabled: true
r2dbc:
url: r2dbc:sqlserver://<just_host>:<port>
username: <db_username>
password: <db_password>
name: <db_name>
spring.data.r2dbc.repositories.enabled: true is optional here.
If you are creating custom bean, you can create bean like below. Please note that I'm returning ConnectionFactory rather than MssqlConnectionFactory.
#Bean
public ConnectionFactory connectionFactory() {
return new MssqlConnectionFactory(
MssqlConnectionConfiguration.builder()
.host("just_host")
.database("db_name")
.port(1433)
.username("db_username")
.password("db_password")
.build());
}

Related

Getting DnsWithResponseCodeException and NameNotFoundException while connecting to mongo from spring boot app

I am currently facing a weird issue. I CAN connect to the MongoDB server from MongoDB Compass and IntelliJ. But when I try to connect to the Mongo database from my Java application it continuously throws
Caused by: com.mongodb.spi.dns.DnsWithResponseCodeException: DNS name not found [response code 3]
Caused by: javax.naming.NameNotFoundException: DNS name not found [response code 3]
Background:
I have a simple Java application and to run that I use Gradle's bootRun task. I have added mongodb-driver-core, mongodb-driver-sync, and bson dependencies from org.mongodb and spring-data-mongodb from org.springframework.data. I have added the connection string as a property in a yml file.
The connection string is:
mongodb+srv://<username>:<password>#<domain>/<dbname>?ssl=false&authMechanism=PLAIN&connectTimeoutMS=30000&maxIdleTimeMS=600000
and here is my mongo config class:
#Configuration
public class MongoConfiguration {
#Bean
public MongoClient mongoClient(#Value("${spring.data.mongodb.uri}") String url) {
return MongoClients.create(url);
}
#Bean
public MongoTemplate mongoTemplate(MongoClient mongo,
#Value("${mongo.database}") String databaseName) {
MongoTemplate mongoTemplate = new MongoTemplate(mongo, databaseName);
mongoTemplate.createCollection("Collection_Name");
return mongoTemplate;
}
}
The weird part is even if the application is throwing DNS name not found error, I can connect to the database from MongoDB Compass with the same connection string.
Also, one important thing to note here is the same code works for all of my teammates. They can access the database from the code.
I have tried a few things:
Flush DNS cache on Windows
Added inbound and outbound for the port (30000 in my case) in the firewall
Remove the srv part from my connection URI according to the answer in this post
but none of them worked yet. Any help is appreciated!
Here's my complete stacktrace:
[INFO ] 2023-01-28 10:11:19 o.m.d.cluster [cluster-ClusterId{value='63d53b1769d90d388d824a76', description='null'}-srv-<domain>]: Exception while resolving SRV records
com.mongodb.MongoConfigurationException: Failed looking up SRV record for '_mongodb._tcp.<domain>'.
at com.mongodb.internal.dns.DefaultDnsResolver.resolveHostFromSrvRecords(DefaultDnsResolver.java:92) ~[mongodb-driver-core-4.8.2.jar:?]
at com.mongodb.internal.connection.DefaultDnsSrvRecordMonitor$DnsSrvRecordMonitorRunnable.run(DefaultDnsSrvRecordMonitor.java:80) [mongodb-driver-core-4.8.2.jar:?]
at java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: com.mongodb.spi.dns.DnsWithResponseCodeException: DNS name not found [response code 3]
at com.mongodb.internal.dns.JndiDnsClient.getResourceRecordData(JndiDnsClient.java:52) ~[mongodb-driver-core-4.8.2.jar:?]
at com.mongodb.internal.dns.DefaultDnsResolver.resolveHostFromSrvRecords(DefaultDnsResolver.java:74) ~[mongodb-driver-core-4.8.2.jar:?]
... 2 more
Caused by: javax.naming.NameNotFoundException: DNS name not found [response code 3]
at com.sun.jndi.dns.DnsClient.checkResponseCode(DnsClient.java:661) ~[jdk.naming.dns:?]
at com.sun.jndi.dns.DnsClient.isMatchResponse(DnsClient.java:579) ~[jdk.naming.dns:?]
at com.sun.jndi.dns.DnsClient.doUdpQuery(DnsClient.java:427) ~[jdk.naming.dns:?]
at com.sun.jndi.dns.DnsClient.query(DnsClient.java:212) ~[jdk.naming.dns:?]
at com.sun.jndi.dns.Resolver.query(Resolver.java:81) ~[jdk.naming.dns:?]
at com.sun.jndi.dns.DnsContext.c_getAttributes(DnsContext.java:434) ~[jdk.naming.dns:?]
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_getAttributes(ComponentDirContext.java:235) ~[?:?]
Caused by: com.mongodb.spi.dns.DnsWithResponseCodeException: DNS name not found [response code 3]
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:141) ~[?:?]
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:129) ~[?:?]
at javax.naming.directory.InitialDirContext.getAttributes(InitialDirContext.java:142) ~[?:?]
at com.mongodb.internal.dns.JndiDnsClient.getResourceRecordData(JndiDnsClient.java:41) ~[mongodb-driver-core-4.8.2.jar:?]
at com.mongodb.internal.dns.DefaultDnsResolver.resolveHostFromSrvRecords(DefaultDnsResolver.java:74) ~[mongodb-driver-core-4.8.2.jar:?]
... 2 more
[WARN ] 2023-01-28 10:11:19 o.s.d.c.CustomConversions [main]: Registering converter from class java.time.LocalDateTime to class org.joda.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type; You might want to check your annotation setup at the converter implementation
[WARN ] 2023-01-28 10:11:19 o.s.d.c.CustomConversions [main]: Registering converter from class java.time.LocalDateTime to class org.joda.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type; You might want to check your annotation setup at the converter implementation
Caused by: javax.naming.NameNotFoundException: DNS name not found [response code 3]

Spring boot - Connection reset by peer under heavy load

We are seeing some errors related to connection reset in Production under heavy load.
Basically the flow is
Microservice 1 -> Load Balancer() -> Microservice 2
Error message is
Stack trace:
|_ checkpoint ? Request to post
http://LoadbalancerURL/process [Default web client]
Error has been observed at the following site(s):
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
io.netty.channel.unix.Errors$NativeIoException: readAddress(..) failed: Connection reset by peer
My question is how do we troubleshoot this issue.
Do we need to take tcpdump? if yes then what should I look for?
Possible workaround I could think of is use exponential retry. Any idea where I could insert retry logic in below code?
Below is the code snipnet on how we are calling the url from microservice 1
webclient
.create()
.post()
.uri(url)
.bodyValue(input)
.retrieve()
.toEntity(object.class)
.log()
.subscribe(
onSuccess -> {
//somelogic
},
onError -> {
//somelogic
},
()->{
})

Zuul: automatic rerouting incoming requests to other service instance in case of unavailable service

I have configured Zuul with Eureka in a way, that 3 identical instances of a service are working parallely. I am calling the gateway on the port 8400, which routes incoming requests to ports 8420, 8430 and 8440 in a round-robin manner. It works smoothly. Now, if I switching off one of the 3 services, a small amount of incoming requests will go wrong with the following exception:
com.netflix.zuul.exception.ZuulException: Filter threw Exception
=> 1: java.util.concurrent.FutureTask.report(FutureTask.java:122)
=> 3: hu.perit.spvitamin.core.batchprocessing.BatchProcessor.process(BatchProcessor.java:106)
caused by: com.netflix.zuul.exception.ZuulException: Filter threw Exception
=> 1: com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:227)
caused by: org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException: com.netflix.zuul.exception.ZuulException: Forwarding error
=> 1: org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.run(RibbonRoutingFilter.java:124)
caused by: com.netflix.zuul.exception.ZuulException: Forwarding error
=> 1: org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.handleException(RibbonRoutingFilter.java:198)
caused by: com.netflix.client.ClientException: com.netflix.client.ClientException
=> 1: com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:118)
caused by: java.lang.RuntimeException: org.apache.http.NoHttpResponseException: scalable-service-2:8430 failed to respond
=> 1: rx.exceptions.Exceptions.propagate(Exceptions.java:57)
caused by: org.apache.http.NoHttpResponseException: scalable-service-2:8430 failed to respond
=> 1: org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
My Zuul routing looks like this:
### Zuul routes
zuul.routes.scalable-service.path=/scalable/**
#Authorization header will be forwarded to scalable-service
zuul.routes.scalable-service.sensitiveHeaders: Cookie,Set-Cookie
zuul.routes.scalable-service.serviceId=template-scalable-service
It takes a while until Eureka discovers the service is not available any more.
My question is: Is there a possibility, to configure Zuul so that in case of a NoHttpResponseException, it forwards the requests to another available instance in the pool?
Eureka, by default, requires lease to be renewed every 90s. That is, if a service instance doesn't get its lease renewed in 90s, Eureka server will evict the instance. In your case, the instance has not been evicted yet - the renew window for the instance was valid.
For this, you can decrease the renew duration through config setup at eureka client and eureka server as described here.
Note: If you hit the actuator /shutdown endpoint, the instance is immediately evicted
Finally I found the solution to the problem. The appropriate search phrase was 'fault tolerance'. The key is the autoretry config in the following application.properties file. The value of template-scalable-service.ribbon.MaxAutoRetriesNextServer must be set at least to 6 in case of 3 pooled services to achieve full fault tolerance. With that setup I can kill 2 of 3 services any time, no incoming request will go wrong. Finally I have set it to 10, there is no unnecessary increase of timeout, hystrix will break the line.
### Eureka config
eureka.instance.hostname=${hostname:localhost}
eureka.instance.instanceId=${eureka.instance.hostname}:${spring.application.name}:${server.port}
eureka.instance.non-secure-port-enabled=false
eureka.instance.secure-port-enabled=true
eureka.instance.secure-port=${server.port}
eureka.instance.lease-renewal-interval-in-seconds=5
eureka.instance.lease-expiration-duration-in-seconds=10
eureka.datacenter=perit.hu
eureka.environment=${EUREKA_ENVIRONMENT_PROFILE:dev}
eureka.client.serviceUrl.defaultZone=${EUREKA_SERVER:https://${server.fqdn}:${server.port}/eureka}
eureka.client.server.waitTimeInMsWhenSyncEmpty=0
eureka.client.registry-fetch-interval-seconds=5
eureka.dashboard.path=/gui
eureka.server.enable-self-preservation=false
eureka.server.expected-client-renewal-interval-seconds=10
eureka.server.eviction-interval-timer-in-ms=2000
### Ribbon
ribbon.IsSecure=true
ribbon.NFLoadBalancerPingInterval=5
ribbon.ConnectTimeout=30000
ribbon.ReadTimeout=120000
### Zuul config
zuul.host.connectTimeoutMillis=30000
zuul.host.socketTimeoutMillis=120000
zuul.host.maxTotalConnections=2000
zuul.host.maxPerRouteConnections=200
zuul.retryable=true
### Zuul routes
#template-scalable-service
zuul.routes.scalable-service.path=/scalable/**
#Authorization header will be forwarded to scalable-service
zuul.routes.scalable-service.sensitiveHeaders=Cookie,Set-Cookie
zuul.routes.scalable-service.serviceId=template-scalable-service
# Autoretry config for template-scalable-service
template-scalable-service.ribbon.MaxAutoRetries=0
template-scalable-service.ribbon.MaxAutoRetriesNextServer=10
template-scalable-service.ribbon.OkToRetryOnAllOperations=true
#template-auth-service
zuul.routes.auth-service.path=/auth/**
#Authorization header will be forwarded to scalable-service
zuul.routes.auth-service.sensitiveHeaders=Cookie,Set-Cookie
zuul.routes.auth-service.serviceId=template-auth-service
# Autoretry config for template-auth-service
template-auth-service.ribbon.MaxAutoRetries=0
template-auth-service.ribbon.MaxAutoRetriesNextServer=0
template-auth-service.ribbon.OkToRetryOnAllOperations=false
### Hystrix
hystrix.command.default.execution.timeout.enabled=false
Beside of this, I have a profile specific setup in application-discovery.properties
#Microservice environment
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=true
spring.cloud.loadbalancer.ribbon.enabled=true
I start my server in a docker container like this:
services:
discovery:
container_name: discovery
image: template-eureka
environment:
#agentlib for remote debugging
- JAVA_OPTS=-DEUREKA_SERVER=https://discovery:8400/eureka -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
- TEMPLATE_EUREKA_OPTS=-Dspring.profiles.active=default,dev,discovery
- EUREKA_ENVIRONMENT_PROFILE=dev
ports:
- '8400:8400'
- '5500:5005'
networks:
- back-tier-net
- monitoring
hostname: 'discovery'
See the complete solution in GitHub.

keycloak policy enforcer spring boot

Keycloak policy enforcer not working, Sprint boot application.
I use spring boot v 2.3.1 with Keycloak version 10.0.2, i need setup policy enforcer into my app, autnentication part with keycloak work, but if i add policy enforcer config into application.properties, un have an error
===================>application.properties file:
server.port = 8082
# keycloak config
keycloak.realm = my-realm
keycloak.auth-server-url = http://localhost:8080/auth
keycloak.resource = resource_server
keycloak.credentials.secret = 1adb9e31-cd6a-4eb5-95c5-6a45e972b64a
keycloak.ssl-required=external
keycloak.public-client = true
keycloak.bearer-only = true
#keycloak.verify-token-audience = true
keycloak.cors=true
keycloak.use-resource-role-mappings = true
keycloak.confidential-port=0
keycloak.principal-attribute=preferred_username
keycloak.policy-enforcer-config.enforcement-mode= PERMISSIVE
keycloak.policy-enforcer-config.lazy-load-paths=true
keycloak.policy-enforcer-config.paths[0].name=page_resource
keycloak.policy-enforcer-config.paths[0].path=/uma-protected-resource
keycloak.policy-enforcer-config.paths[0].methods[0].method=GET
keycloak.policy-enforcer-config.paths[0].methods[0].scopes[0]= view
================>test user evaluation in keycloak:
Result
*PERMIT
Scopes
*view
*edit
*delete
Policies
*edit_permission_resource(User-Managed Policy)
decision was PERMIT by AFFIRMATIVE decision. Granted Scopes: edit.
*view_permission_resource(User-Managed Policy)
decision was PERMIT by AFFIRMATIVE decision. Granted Scopes: view.
*delete_permission_resource(User-Managed Policy)
decision was PERMIT by AFFIRMATIVE decision. Granted Scopes: delete.
================>** Error logs**:
java.lang.RuntimeException: Failed to obtain policy enforcer
at org.keycloak.adapters.KeycloakDeployment.getPolicyEnforcer....
at org.keycloak.adapters.AuthenticatedActionsHandler.corsRequest...
at ...
at ...
Caused by: java.lang.RuntimeException: Could not find resource
at ...
at ...
Caused by: Caused by: org.keycloak.authorization.client.util.HttpResponseException: Unexpected response from server: 401 / Unauthorized
at ...
at ...
i use et user token with the right permissions, but i don't know why it doesn't work.
I think, he can't find the resource on kaycloak, but he is there with the right rights
client in keycloak: resource_server
https://i.stack.imgur.com/d3huA.png
https://i.stack.imgur.com/o9xDc.png
resource in keycloak
https://i.stack.imgur.com/mslnu.png
Thanks for your help :)

Connecting to as400 JDBC on Play Framework

I'm having issues making a connection to an AS400 database inside of Play!.
My application.conf looks like:
db.default.driver="com.ibm.as400.access.AS400JDBCDriver"
db.default.url="jdbc:as400://SERVER;libraries=A,B,C;toolbox trace=all;trace=true"
db.default.username="user"
db.default.password="password"
I've set up jt400 in the classpath, and I can see under "external libraries" that it shows up and is available. But essentially I get an error message about failing to connect (on user/password I know works) and failure to execute isValid(), which is a function that can not be found inside of AS400JDBCConnection class.
[error] c.z.h.p.PoolBase - HikariPool-1 - Failed to execute isValid() for connection, configure connection test query. (com.ibm.as400.access.AS400JDBCConnection.isValid(I)Z)
[error] application -
! #72265nf0a - Internal server error, for (GET) [/] ->
play.api.Configuration$$anon$1: Configuration error[Cannot connect to database [default]]
at play.api.Configuration$.configError(Configuration.scala:154)
at play.api.Configuration.reportError(Configuration.scala:806)
at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:48)
at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:42)
at scala.collection.immutable.List.foreach(List.scala:381)
at play.api.db.DefaultDBApi.connect(DefaultDBApi.scala:42)
at play.api.db.DBApiProvider.get$lzycompute(DBModule.scala:72)
at play.api.db.DBApiProvider.get(DBModule.scala:62)
at play.api.db.DBApiProvider.get(DBModule.scala:58)
at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:81)
Caused by: play.api.Configuration$$anon$1: Configuration error[Failed to initialize pool: com.ibm.as400.access.AS400JDBCConnection.isValid(I)Z]
at play.api.Configuration$.configError(Configuration.scala:154)
at play.api.PlayConfig.reportError(Configuration.scala:996)
at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:70)
at play.api.db.PooledDatabase.createDataSource(Databases.scala:199)
at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
at play.api.db.DefaultDatabase.dataSource(Databases.scala:121)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:142)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:138)
at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:44)
at play.api.db.DefaultDBApi$$anonfun$connect$1.apply(DefaultDBApi.scala:42)
Caused by: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: com.ibm.as400.access.AS400JDBCConnection.isValid(I)Z
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:512)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:105)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:71)
at play.api.db.HikariCPConnectionPool$$anonfun$1.apply(HikariCPModule.scala:58)
at play.api.db.HikariCPConnectionPool$$anonfun$1.apply(HikariCPModule.scala:54)
at scala.util.Try$.apply(Try.scala:192)
at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:54)
at play.api.db.PooledDatabase.createDataSource(Databases.scala:199)
at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
at play.api.db.DefaultDatabase.dataSource(Databases.scala:121)
Caused by: java.lang.AbstractMethodError: com.ibm.as400.access.AS400JDBCConnection.isValid(I)Z
at com.zaxxer.hikari.pool.PoolBase.checkDriverSupport(PoolBase.java:400)
at com.zaxxer.hikari.pool.PoolBase.setupConnection(PoolBase.java:375)
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:346)
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:506)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:105)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:71)
at play.api.db.HikariCPConnectionPool$$anonfun$1.apply(HikariCPModule.scala:58)
at play.api.db.HikariCPConnectionPool$$anonfun$1.apply(HikariCPModule.scala:54)
at scala.util.Try$.apply(Try.scala:192)
at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:54)
I'm able to connect in other java-based projects using something like:
try {
Class.forName("com.ibm.as400.access.AS400JDBCDriver");
Connection con = DriverManager.getConnection("jdbc:as400://" +
ApplicationAuthentication.server + "/" +
ApplicationAuthentication.library,
ApplicationAuthentication.user,
ApplicationAuthentication.password
);
} catch (Exception e) {
System.err.println(e);
throw new WebApplicationException(genericError, Response.Status.UNAUTHORIZED);
}
Guessing from the stacktrace, it appears that the connection returned from your driver is not playing well with the connection Hikari Connection Pool. Hikari is default connection pool in playframework.
Specifically, your exception trace shows that the Hikari CP is attempting to call isValid method on the connection object returned by your JDBC driver and then failing with java.lang.AbstractMethodError.
You can try switching to BoneCP connection pool and see if it helps. You can also check comments on this issue on hikari github issue list
Try adding the following to application.config
db.default.hikaricp.connectionTestQuery="SELECT 1"
Not tested in Play Framework but I had similar issue on spring framework and solved in that way.
Use liquibase datasource like below with connection-test-query
#Bean
#LiquibaseDataSource
public DataSource liquibaseDataSource() {
HikariDataSource dataSource = (HikariDataSource) DataSourceBuilder.create().url("url")
.username("username")
.password("password")
.type(HikariDataSource.class).build();
dataSource.setConnectionTestQuery("select 1 from sysibm.sysdummy1");
return dataSource;
}

Categories

Resources