My springboot microservice depends on AS400 DB2 which may be down when the service starts up.
The service has a configuration bean which has autowired JpaRepository based repositories.
During startup, when DB2 is down I get following message:
"org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set"
So the services fails to start up and remains dead till forcefully rebooted.
If I set JVM parameter "-Dhibernate.dialect=org.hibernate.dialect.DB2400Dialect", the service starts up and I can make requests to the service when DB2 comes up. It feels like a hack, so I wonder if there is the right way to deal with this issue for springboot services?
I saw this thread, but it doesn't answer my question.
Basically what I am looking for is somehow start the microservice with those autowired repositories even if DB is down at the moment so that later, when the actual request comes, the connection to the DB could be restored and request serviced.
Have you tried to specify Hibernate dialect for your DBMS flavour in src/main/resources/application.properties like:
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.DB2400Dialect
?
Spring Boot autodetects dialect on startup if database is up but there is nothing inappropriate to specify your dialect explicitly in source code.
Related
I am using spring.data.elasticsearch with Elasticsearch 7.14.1 in my Spring Boot (2.5.4) application.
My application.properties is something like this
spring.elasticsearch.rest.uris=elasticsearch:9200
spring.data.elasticsearch.cluster=elasticsearch:9200
spring.data.elasticsearch.repositories.enabled=true
This works fine as long as the invocation is from localhost, no issues. However, when I try to bring up my Spring Boot container, I see a failure with NoReachableHostException
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.data.elasticsearch.client.NoReachableHostException: Host 'localhost:9200' not reachable. Cluster state is offline.
blah-blah-service
Caused by: org.springframework.data.elasticsearch.client.NoReachableHostException: Host **'localhost:9200'** not reachable. Cluster state is offline.
blah-blah-service
at org.springframework.data.elasticsearch.client.reactive.SingleNodeHostProvider.lambda$lookupActiveHost$3(SingleNodeHostProvider.java:101)
Clearly, my suggestion to use "elasticsearch" host (defined network, that is tested and accessible from within and outside docker containers), hasn't gone well with Spring Data for whatever reason. I have even used
#PropertySource("classpath:mysearch.properties")
in my application to try and coax these properties into the app, but doesn't look like anything works. Is there something I am missing in my Elasticsearch configuration or otherwise?
PS: I have exercised curl http://elasticsearch:9200 from within the container and find no issues
These configurations are Spring Boot specific, Spring Data Elasticsearch does not use them. But as far as I can see, you are configuring the transport client (cluster entry, should not be used anyway) and the imperative REST client, but according to the error message you are using the reactive REST client.
According to the Spring Boot documentation you would need to set spring.data.elasticsearch.client.reactive.endpoints
In the .properties file, I used the below and solved the issue for me;
spring.elasticsearch.rest.uris=http://localhost:<port_number>
spring.data.elasticsearch.client.reactive.endpoints=localhost:<port_number>
We have a Spring-Boot application exposing some REST endpoints. We allow for this application to be operated standalone (as executable jar) or as a war to be deployed in a wildfly-11 application-server.
The class defining the REST-endpoints is marked #RestController #Transactional(REQUIRES_NEW) (both on class level, obviously). When running standalone, everything works as expected but when deployed in wildfly, the rollback on exceptions does not work. We established this by sending the exact same REST-message while operating on the exact same database.
We have confirmed via debugging that the final frames of the stacktrace is identical in both cases and especially in both cases we see a transactional-proxy around our REST-controller bean.
One difference would be, that within wildfly the application will use a jndi-datasource, prepared by wildfly while standalone the spring-boot will manage the database-connections.
Any idea what is wrong here?
Edit
I just tried explicitly invoking setRollbackOnly on the JtaTransactionmanager from within my code. The transaction will still commit. This sort of looks like a bug in Spring Boot to me.
Edit 2
Debugging further reveals that the transaction seems to be set to autocommit - every statement is immediately written to the database. This seems to be in violation to the annotation #Transactional and also to the fact that Spring creates a transactional proxy around my bean.
It's not a full answer - just a reasoning. JNDI is usally used at the app server layer whereas JDBC - at the application layer. At the App server layer are used global transaction settins that are overriding app settings. Follow the spring doc to get more
For reasons beyond my understanding the default transactional behaviour when deploying a spring-boot webapp to an application-server is auto-commit.
The solution to this problem is to enrich your application-configuration with the property spring.datasource.tomcat.default-auto-commit=false
I'm trying to make Spring Boot application with Flyway (and Hikari pool) to start the server even when the DB is not available at that time.
I need to support cases when:
1. DB is not available when applicaition starts (it should run Flyway after DB starts, it can be up to 30 mins).
2. DB goes offline during the application lifetime and then goes back up.
I got a problem with the first case, Flyway always tries to do migrations even when DB is not available and application stops.
I tried adding spring.datasource.continue-on-error: true but Flyway ignores that, and I couldn't find any flyway configuration that would allow such operation.
Is it possible or should I wrap Flyway and do it myself?
Spring boot 2.1.4
A couple of points to consider
What is the desired behavior of the application when the DB is really not available when the instance of java application? Ok, so flyway won't start, but how the application will be able to handle requests that will have to reach the database?
Flyway itself relies on DataSource bean, maybe on hibernate if you use it, and these are much more complicated infrastructures than flyway itself?
Maybe if the database is not available the application won't need to start at all?
Instead it worth to rely on orchestrators (like kubernetes, ECS or whatever that will recognize that the application didn't start and will try to retrigger the start again, again, and again till the database will be ready)?
This is my recommendation in general.
Now, assuming find answers to all these questions and still, want to proceed with this path:
Spring Boot by itself works like this when it comes to flyway integration:
If the relevant classes (Flyway class) exist on classpath and spring.flyway.enabled=true then the bean of flyway starts and spring boot does its magic.
Technically the relevant auto configuration can be found in class org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration (org.springframework.boot:spring-boot-autoconfigure module)
I think the way to go is to disable flyway, and given that fact that beans like DataSource are available (somehow) - create a Flyway Bean by yourself and trigger the migration in some kind of loop in the background that will exit only if the migration actually succeeds (or already applied)
I have a project based in Spring Web model-view-controller (MVC) framework. The version of the Spring Web model-view-controller (MVC) framework is 3.2.8 deployed on a WebLogic Server Version: 12.1.2.0.0
I have this error in 1 query
Caused By: java.lang.RuntimeException: java.sql.SQLException:
The transaction is no longer active - status: 'Marked rollback. [Reason=weblogic.transaction.internal.TimedOutException: Transaction timed out after 31 seconds
BEA1-000D9470C1367F28EDB9]'.
No further JDBC access is allowed within this transaction., criteria [ com.tdk.books.domain.ProductSearchCriteria#c5f15d5c ], sql [ select PRODUCT_ID from V_BOOKS where category_id = ? ]
even I put a timeout of 10000 in the service method
#Transactional(timeout=10000, propagation = Propagation.REQUIRES_NEW)
Root Cause from Oracle Community:
Usuallly this happens when a transaction is finished, but this fact is
ignored and an app tries to continue processing and to issue JDBC
statements that happen outside of the TX. The source of this problem
could be a Connection object that is passed around through a sequence
of methods that use the connection. One of such methods commits the TX
thus invalidating the connection.
Resource Link: https://community.oracle.com/thread/734370
Some suggestions are found to solve the issue.
First Suggestion:
Please try changing your weblogic datasource settings from Non - XA to
XA. You should get rid of this exception.
Resource Link: The transaction is no longer active - status: 'Committed'
Second Suggestion:
Uncheck the Supports Global Transactions restart the server.
Resource Link: In PRPC ERROR: The transaction is no longer active - status: 'Committed'
Third Suggestion:
The real solution of this problem is asynchronous processing. But it
might be possible that it's not suitable in your case.
First one If you are making any jdbc call to Oracle, then you can set
the query time out whn you execute the query on database. And after
query timeout, Oracle will give you an exception that you can handle
it. So basically in this case you are not cancelling your EJB request
actually. But it might solve your problem.
Resource Link: https://coderanch.com/t/68079/transaction-rollback-commit
I'm using eclipselink 2.4 in a JAX-RS (Jersey) application.
In my base controller, I connect to my database, but since the entity manager only really connects when a query is executed, an exception is thrown.
Is there a way I could determine if I can connect to a database after I get the EntityManager object so that I can handle the exception myself (and fail over manually to another database).
EDIT: assume I cannot change the underlying DBMS at all.
You could create a ServletContextListener and run a query on startup for your application. However if it fails you are out of luck for the error handling I guess.
You should really get a clustered HA database.